From c39d7a632603c944732787e3ba1b77e26fccc3c1 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 27 Feb 2020 11:51:43 -0500
Subject: [PATCH 01/62] fix exported variable not respecting linkage
---
src/ir.cpp | 1 +
test/standalone/global_linkage/build.zig | 23 +++++++++++++++++++++++
test/standalone/global_linkage/main.zig | 9 +++++++++
test/standalone/global_linkage/obj1.zig | 7 +++++++
test/standalone/global_linkage/obj2.zig | 7 +++++++
5 files changed, 47 insertions(+)
create mode 100644 test/standalone/global_linkage/build.zig
create mode 100644 test/standalone/global_linkage/main.zig
create mode 100644 test/standalone/global_linkage/obj1.zig
create mode 100644 test/standalone/global_linkage/obj2.zig
diff --git a/src/ir.cpp b/src/ir.cpp
index 7de45ebcd3..895cfa334c 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -17841,6 +17841,7 @@ static IrInstGen *ir_analyze_instruction_export(IrAnalyze *ira, IrInstSrcExport
}
} break;
case ZigTypeIdInt:
+ want_var_export = true;
break;
case ZigTypeIdVoid:
case ZigTypeIdBool:
diff --git a/test/standalone/global_linkage/build.zig b/test/standalone/global_linkage/build.zig
new file mode 100644
index 0000000000..c6c45c008a
--- /dev/null
+++ b/test/standalone/global_linkage/build.zig
@@ -0,0 +1,23 @@
+const Builder = @import("std").build.Builder;
+
+pub fn build(b: *Builder) void {
+ const mode = b.standardReleaseOptions();
+ const target = b.standardTargetOptions(null);
+
+ const obj1 = b.addStaticLibrary("obj1", "obj1.zig");
+ obj1.setBuildMode(mode);
+ obj1.setTheTarget(target);
+
+ const obj2 = b.addStaticLibrary("obj2", "obj2.zig");
+ obj2.setBuildMode(mode);
+ obj2.setTheTarget(target);
+
+ const main = b.addTest("main.zig");
+ main.setBuildMode(mode);
+ main.setTheTarget(target);
+ main.linkLibrary(obj1);
+ main.linkLibrary(obj2);
+
+ const test_step = b.step("test", "Test it");
+ test_step.dependOn(&main.step);
+}
diff --git a/test/standalone/global_linkage/main.zig b/test/standalone/global_linkage/main.zig
new file mode 100644
index 0000000000..53d953765b
--- /dev/null
+++ b/test/standalone/global_linkage/main.zig
@@ -0,0 +1,9 @@
+const std = @import("std");
+
+extern var obj1_integer: usize;
+extern var obj2_integer: usize;
+
+test "access the external integers" {
+ std.testing.expect(obj1_integer == 421);
+ std.testing.expect(obj2_integer == 422);
+}
diff --git a/test/standalone/global_linkage/obj1.zig b/test/standalone/global_linkage/obj1.zig
new file mode 100644
index 0000000000..95814cda3d
--- /dev/null
+++ b/test/standalone/global_linkage/obj1.zig
@@ -0,0 +1,7 @@
+extern var internal_integer: usize = 1;
+extern var obj1_integer: usize = 421;
+
+comptime {
+ @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal });
+ @export(obj1_integer, .{ .name = "obj1_integer", .linkage = .Strong });
+}
diff --git a/test/standalone/global_linkage/obj2.zig b/test/standalone/global_linkage/obj2.zig
new file mode 100644
index 0000000000..f2d44b2dc0
--- /dev/null
+++ b/test/standalone/global_linkage/obj2.zig
@@ -0,0 +1,7 @@
+extern var internal_integer: usize = 2;
+extern var obj2_integer: usize = 422;
+
+comptime {
+ @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal });
+ @export(obj2_integer, .{ .name = "obj2_integer", .linkage = .Strong });
+}
From a6087a7bc1e7ba5e964e20379f3ea70bd8c25f1e Mon Sep 17 00:00:00 2001
From: Michael Dusan
Date: Fri, 28 Feb 2020 08:30:43 -0500
Subject: [PATCH 02/62] stage1: housekeeping
---
src/all_types.hpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 022a34038e..7277d04359 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -3267,7 +3267,6 @@ struct IrInstSrcContainerInitList {
struct IrInstSrcContainerInitFieldsField {
Buf *name;
AstNode *source_node;
- TypeStructField *type_struct_field;
IrInstSrc *result_loc;
};
From fba39ff331a84f1a32d076ccbb8b87cd02ea7121 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 24 Feb 2020 01:38:21 -0500
Subject: [PATCH 03/62] restructuring std.Target for OS version ranges, pass 1
---
lib/std/builtin.zig | 32 +++-
lib/std/target.zig | 430 ++++++++++++++++++++++++++++++++++----------
src/analyze.cpp | 2 +-
test/tests.zig | 30 ++--
4 files changed, 383 insertions(+), 111 deletions(-)
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index 5440de4d3b..1bb8fd85ae 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -398,7 +398,37 @@ 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),
+ };
+ }
};
/// This data structure is used by the Zig language code generation and
diff --git a/lib/std/target.zig b/lib/std/target.zig
index cf83bb1f7a..84056eae02 100644
--- a/lib/std/target.zig
+++ b/lib/std/target.zig
@@ -1,30 +1,53 @@
const std = @import("std.zig");
const mem = std.mem;
const builtin = std.builtin;
+const Version = std.builtin.Version;
/// TODO Nearly all the functions in this namespace would be
/// better off if https://github.com/ziglang/zig/issues/425
/// was solved.
-pub const Target = union(enum) {
- Native: void,
- Cross: Cross,
+pub const Target = struct {
+ cpu: Cpu,
+ os: Os,
+ abi: Abi,
- pub const Os = enum {
+ /// The version ranges here represent the minimum OS version to be supported
+ /// and the maximum OS version to be supported. The default values represent
+ /// the range that the Zig Standard Library bases its abstractions on.
+ ///
+ /// The minimum version of the range is the main setting to tweak for a target.
+ /// Usually, the maximum target OS version will remain the default, which is
+ /// the latest released version of the OS.
+ ///
+ /// To test at compile time if the target is guaranteed to support a given OS feature,
+ /// one should check that the minimum version of the range is greater than or equal to
+ /// the version the feature was introduced in.
+ ///
+ /// To test at compile time if the target certainly will not support a given OS feature,
+ /// one should check that the maximum version of the range is less than the version the
+ /// feature was introduced in.
+ ///
+ /// If neither of these cases apply, a runtime check should be used to determine if the
+ /// target supports a given OS feature.
+ ///
+ /// Binaries built with a given maximum version will continue to function on newer operating system
+ /// versions. However, such a binary may not take full advantage of the newer operating system APIs.
+ pub const Os = union(enum) {
freestanding,
ananas,
cloudabi,
dragonfly,
- freebsd,
+ freebsd: Version.Range,
fuchsia,
ios,
kfreebsd,
- linux,
+ linux: LinuxVersionRange,
lv2,
- macosx,
- netbsd,
- openbsd,
+ macosx: Version.Range,
+ netbsd: Version.Range,
+ openbsd: Version.Range,
solaris,
- windows,
+ windows: WindowsVersion.Range,
haiku,
minix,
rtems,
@@ -48,14 +71,230 @@ pub const Target = union(enum) {
uefi,
other,
+ /// See the documentation for `Os` for an explanation of the default version range.
+ pub fn defaultVersionRange(tag: @TagType(Os)) Os {
+ switch (tag) {
+ .freestanding => return .freestanding,
+ .ananas => return .ananas,
+ .cloudabi => return .cloudabi,
+ .dragonfly => return .dragonfly,
+ .freebsd => return .{
+ .freebsd = Version.Range{
+ .min = .{ .major = 12, .minor = 0 },
+ .max = .{ .major = 12, .minor = 1 },
+ },
+ },
+ .fuchsia => return .fuchsia,
+ .ios => return .ios,
+ .kfreebsd => return .kfreebsd,
+ .linux => return .{
+ .linux = .{
+ .range = .{
+ .min = .{ .major = 3, .minor = 16 },
+ .max = .{ .major = 5, .minor = 5, .patch = 5 },
+ },
+ .glibc = .{ .major = 2, .minor = 17 },
+ },
+ },
+ .lv2 => return .lv2,
+ .macosx => return .{
+ .min = .{ .major = 10, .minor = 13 },
+ .max = .{ .major = 10, .minor = 15, .patch = 3 },
+ },
+ .netbsd => return .{
+ .min = .{ .major = 8, .minor = 0 },
+ .max = .{ .major = 9, .minor = 0 },
+ },
+ .openbsd => return .{
+ .min = .{ .major = 6, .minor = 6 },
+ .max = .{ .major = 6, .minor = 6 },
+ },
+ solaris => return .solaris,
+ windows => return .{
+ .windows = .{
+ .min = .win8_1,
+ .max = .win10_19h1,
+ },
+ },
+ haiku => return .haiku,
+ minix => return .minix,
+ rtems => return .rtems,
+ nacl => return .nacl,
+ cnk => return .cnk,
+ aix => return .aix,
+ cuda => return .cuda,
+ nvcl => return .nvcl,
+ amdhsa => return .amdhsa,
+ ps4 => return .ps4,
+ elfiamcu => return .elfiamcu,
+ tvos => return .tvos,
+ watchos => return .watchos,
+ mesa3d => return .mesa3d,
+ contiki => return .contiki,
+ amdpal => return .amdpal,
+ hermit => return .hermit,
+ hurd => return .hurd,
+ wasi => return .wasi,
+ emscripten => return .emscripten,
+ uefi => return .uefi,
+ other => return .other,
+ }
+ }
+
+ pub const LinuxVersionRange = struct {
+ range: Version.Range,
+ glibc: Version,
+
+ pub fn includesVersion(self: LinuxVersionRange, ver: Version) bool {
+ return self.range.includesVersion(ver);
+ }
+ };
+
+ /// Based on NTDDI version constants from
+ /// https://docs.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt
+ pub const WindowsVersion = enum(u32) {
+ nt4 = 0x04000000,
+ win2k = 0x05000000,
+ xp = 0x05010000,
+ ws2003 = 0x05020000,
+ vista = 0x06000000,
+ win7 = 0x06010000,
+ win8 = 0x06020000,
+ win8_1 = 0x06030000,
+ win10 = 0x0A000000,
+ win10_th2 = 0x0A000001,
+ win10_rs1 = 0x0A000002,
+ win10_rs2 = 0x0A000003,
+ win10_rs3 = 0x0A000004,
+ win10_rs4 = 0x0A000005,
+ win10_rs5 = 0x0A000006,
+ win10_19h1 = 0x0A000007,
+
+ pub const Range = struct {
+ min: WindowsVersion,
+ max: WindowsVersion,
+
+ pub fn includesVersion(self: Range, ver: WindowsVersion) bool {
+ return @enumToInt(ver) >= @enumToInt(self.min) and @enumToInt(ver) <= @enumToInt(self.max);
+ }
+ };
+
+ pub fn nameToTag(name: []const u8) ?WindowsVersion {
+ const info = @typeInfo(WindowsVersion);
+ inline for (info.Enum.fields) |field| {
+ if (mem.eql(u8, name, field.name)) {
+ return @field(WindowsVersion, field.name);
+ }
+ }
+ return null;
+ }
+ };
+
pub fn parse(text: []const u8) !Os {
+ var it = mem.separate(text, ".");
+ const os_name = it.next().?;
+ const tag = nameToTag(os_name) orelse return error.UnknownOperatingSystem;
+ const version_text = it.rest();
+ const S = struct {
+ fn parseNone(s: []const u8) !void {
+ if (s.len != 0) return error.InvalidOperatingSystemVersion;
+ }
+ fn parseSemVer(s: []const u8, default: Version.Range) !Version.Range {
+ if (s.len == 0) return default;
+ var range_it = mem.separate(s, "...");
+
+ const min_text = range_it.next().?;
+ const min_ver = Version.parse(min_text) catch |err| switch (err) {
+ error.Overflow => return error.InvalidOperatingSystemVersion,
+ error.InvalidCharacter => return error.InvalidOperatingSystemVersion,
+ error.InvalidVersion => return error.InvalidOperatingSystemVersion,
+ };
+
+ const max_text = range_it.next() orelse return Version.Range{
+ .min = min_ver,
+ .max = default.max,
+ };
+ const max_ver = Version.parse(max_text) catch |err| switch (err) {
+ error.Overflow => return error.InvalidOperatingSystemVersion,
+ error.InvalidCharacter => return error.InvalidOperatingSystemVersion,
+ error.InvalidVersion => return error.InvalidOperatingSystemVersion,
+ };
+
+ return Version.Range{ .min = min_ver, .max = max_ver };
+ }
+ fn parseWindows(s: []const u8, default: WindowsVersion.Range) !WindowsVersion.Range {
+ if (s.len == 0) return default;
+ var range_it = mem.separate(s, "...");
+
+ const min_text = range_it.next().?;
+ const min_ver = WindowsVersion.nameToTag(min_text) orelse
+ return error.InvalidOperatingSystemVersion;
+
+ const max_text = range_it.next() orelse return WindowsVersion.Range{
+ .min = min_ver,
+ .max = default.max,
+ };
+ const max_ver = WindowsVersion.nameToTag(max_text) orelse
+ return error.InvalidOperatingSystemVersion;
+
+ return WindowsVersion.Range{ .min = min_ver, .max = max_ver };
+ }
+ };
+ const default = defaultVersionRange(tag);
+ switch (tag) {
+ .freestanding => return Os{ .freestanding = try S.parseNone(version_text) },
+ .ananas => return Os{ .ananas = try S.parseNone(version_text) },
+ .cloudabi => return Os{ .cloudabi = try S.parseNone(version_text) },
+ .dragonfly => return Os{ .dragonfly = try S.parseNone(version_text) },
+ .freebsd => return Os{ .freebsd = try S.parseSemVer(version_text, default.freebsd) },
+ .fuchsia => return Os{ .fuchsia = try S.parseNone(version_text) },
+ .ios => return Os{ .ios = try S.parseNone(version_text) },
+ .kfreebsd => return Os{ .kfreebsd = try S.parseNone(version_text) },
+ .linux => return Os{
+ .linux = .{
+ .range = try S.parseSemVer(version_text, default.linux.range),
+ .glibc = default.linux.glibc,
+ },
+ },
+ .lv2 => return Os{ .lv2 = try S.parseNone(version_text) },
+ .macosx => return Os{ .macosx = try S.parseSemVer(version_text, default.macosx) },
+ .netbsd => return Os{ .netbsd = try S.parseSemVer(version_text, default.netbsd) },
+ .openbsd => return Os{ .openbsd = try S.parseSemVer(version_text, default.openbsd) },
+ .solaris => return Os{ .solaris = try S.parseNone(version_text) },
+ .windows => return Os{ .windows = try S.parseWindows(version_text, default.windows) },
+ .haiku => return Os{ .haiku = try S.parseNone(version_text) },
+ .minix => return Os{ .minix = try S.parseNone(version_text) },
+ .rtems => return Os{ .rtems = try S.parseNone(version_text) },
+ .nacl => return Os{ .nacl = try S.parseNone(version_text) },
+ .cnk => return Os{ .cnk = try S.parseNone(version_text) },
+ .aix => return Os{ .aix = try S.parseNone(version_text) },
+ .cuda => return Os{ .cuda = try S.parseNone(version_text) },
+ .nvcl => return Os{ .nvcl = try S.parseNone(version_text) },
+ .amdhsa => return Os{ .amdhsa = try S.parseNone(version_text) },
+ .ps4 => return Os{ .ps4 = try S.parseNone(version_text) },
+ .elfiamcu => return Os{ .elfiamcu = try S.parseNone(version_text) },
+ .tvos => return Os{ .tvos = try S.parseNone(version_text) },
+ .watchos => return Os{ .watchos = try S.parseNone(version_text) },
+ .mesa3d => return Os{ .mesa3d = try S.parseNone(version_text) },
+ .contiki => return Os{ .contiki = try S.parseNone(version_text) },
+ .amdpal => return Os{ .amdpal = try S.parseNone(version_text) },
+ .hermit => return Os{ .hermit = try S.parseNone(version_text) },
+ .hurd => return Os{ .hurd = try S.parseNone(version_text) },
+ .wasi => return Os{ .wasi = try S.parseNone(version_text) },
+ .emscripten => return Os{ .emscripten = try S.parseNone(version_text) },
+ .uefi => return Os{ .uefi = try S.parseNone(version_text) },
+ .other => return Os{ .other = try S.parseNone(version_text) },
+ }
+ }
+
+ pub fn nameToTag(name: []const u8) ?@TagType(Os) {
const info = @typeInfo(Os);
- inline for (info.Enum.fields) |field| {
- if (mem.eql(u8, text, field.name)) {
+ inline for (info.Union.fields) |field| {
+ if (mem.eql(u8, name, field.name)) {
return @field(Os, field.name);
}
}
- return error.UnknownOperatingSystem;
+ return null;
}
};
@@ -149,14 +388,39 @@ pub const Target = union(enum) {
}
}
- pub fn parse(text: []const u8) !Abi {
+ pub fn nameToTag(text: []const u8) ?Abi {
const info = @typeInfo(Abi);
inline for (info.Enum.fields) |field| {
if (mem.eql(u8, text, field.name)) {
return @field(Abi, field.name);
}
}
- return error.UnknownApplicationBinaryInterface;
+ return null;
+ }
+
+ pub fn parse(text: []const u8, os: *Os) !Abi {
+ var it = mem.separate(text, ".");
+ const tag = nameToTag(it.next().?) orelse return error.UnknownApplicationBinaryInterface;
+ const version_text = it.rest();
+ if (version_text.len != 0) {
+ if (@as(@TagType(Os), os.*) == .linux and tag.isGnu()) {
+ os.linux.glibc = Version.parse(version_text) catch |err| switch (err) {
+ error.Overflow => return error.InvalidGlibcVersion,
+ error.InvalidCharacter => return error.InvalidGlibcVersion,
+ error.InvalidVersion => return error.InvalidGlibcVersion,
+ };
+ } else {
+ return error.InvalidAbiVersion;
+ }
+ }
+ return tag;
+ }
+
+ pub fn isGnu(abi: Abi) bool {
+ return switch (abi) {
+ .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true,
+ else => false,
+ };
}
};
@@ -179,12 +443,6 @@ pub const Target = union(enum) {
EfiRuntimeDriver,
};
- pub const Cross = struct {
- cpu: Cpu,
- os: Os,
- abi: Abi,
- };
-
pub const Cpu = struct {
/// Architecture
arch: Arch,
@@ -641,20 +899,19 @@ pub const Target = union(enum) {
};
pub const current = Target{
- .Cross = Cross{
- .cpu = builtin.cpu,
- .os = builtin.os,
- .abi = builtin.abi,
- },
+ .cpu = builtin.cpu,
+ .os = builtin.os,
+ .abi = builtin.abi,
};
pub const stack_align = 16;
+ /// TODO add OS version ranges and glibc version
pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
return std.fmt.allocPrint(allocator, "{}-{}-{}", .{
@tagName(self.getArch()),
- @tagName(self.getOs()),
- @tagName(self.getAbi()),
+ @tagName(self.os),
+ @tagName(self.abi),
});
}
@@ -678,7 +935,7 @@ pub const Target = union(enum) {
else => return error.VcpkgNoSuchArchitecture,
};
- const os = switch (target.getOs()) {
+ const os = switch (target.os) {
.windows => "windows",
.linux => "linux",
.macosx => "macos",
@@ -701,16 +958,16 @@ pub const Target = union(enum) {
pub fn zigTripleNoSubArch(self: Target, allocator: *mem.Allocator) ![]u8 {
return std.fmt.allocPrint(allocator, "{}-{}-{}", .{
@tagName(self.getArch()),
- @tagName(self.getOs()),
- @tagName(self.getAbi()),
+ @tagName(self.os),
+ @tagName(self.abi),
});
}
pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
return std.fmt.allocPrint(allocator, "{}-{}-{}", .{
@tagName(self.getArch()),
- @tagName(self.getOs()),
- @tagName(self.getAbi()),
+ @tagName(self.os),
+ @tagName(self.abi),
});
}
@@ -760,11 +1017,11 @@ pub const Target = union(enum) {
diags.arch = arch;
const os_name = it.next() orelse return error.MissingOperatingSystem;
- const os = try Os.parse(os_name);
+ var os = try Os.parse(os_name); // var because Abi.parse can update linux.glibc version
diags.os = os;
const abi_name = it.next();
- const abi = if (abi_name) |n| try Abi.parse(n) else Abi.default(arch, os);
+ const abi = if (abi_name) |n| try Abi.parse(n, &os) else Abi.default(arch, os);
diags.abi = abi;
if (it.next() != null) return error.UnexpectedExtraField;
@@ -817,16 +1074,15 @@ pub const Target = union(enum) {
.features = set,
};
};
- var cross = Cross{
+ return Target{
.cpu = cpu,
.os = os,
.abi = abi,
};
- return Target{ .Cross = cross };
}
pub fn oFileExt(self: Target) []const u8 {
- return switch (self.getAbi()) {
+ return switch (self.abi) {
.msvc => ".obj",
else => ".o",
};
@@ -848,7 +1104,7 @@ pub const Target = union(enum) {
if (self.isWasm()) {
return ".wasm";
}
- switch (self.getAbi()) {
+ switch (self.abi) {
.msvc => return ".lib",
else => return ".a",
}
@@ -858,7 +1114,7 @@ pub const Target = union(enum) {
if (self.isDarwin()) {
return ".dylib";
}
- switch (self.getOs()) {
+ switch (self.os) {
.windows => return ".dll",
else => return ".so",
}
@@ -868,52 +1124,41 @@ pub const Target = union(enum) {
if (self.isWasm()) {
return "";
}
- switch (self.getAbi()) {
+ switch (self.abi) {
.msvc => return "",
else => return "lib",
}
}
- pub fn getOs(self: Target) Os {
- return switch (self) {
- .Native => builtin.os,
- .Cross => |t| t.os,
- };
+ /// Deprecated; access the `os` field directly.
+ pub fn getOs(self: Target) @TagType(Os) {
+ return self.os;
}
+ /// Deprecated; access the `cpu` field directly.
pub fn getCpu(self: Target) Cpu {
- return switch (self) {
- .Native => builtin.cpu,
- .Cross => |cross| cross.cpu,
- };
+ return self.cpu;
+ }
+
+ /// Deprecated; access the `abi` field directly.
+ pub fn getAbi(self: Target) Abi {
+ return self.abi;
}
pub fn getArch(self: Target) Cpu.Arch {
- return self.getCpu().arch;
- }
-
- pub fn getAbi(self: Target) Abi {
- switch (self) {
- .Native => return builtin.abi,
- .Cross => |t| return t.abi,
- }
+ return self.cpu.arch;
}
pub fn getObjectFormat(self: Target) ObjectFormat {
- switch (self) {
- .Native => return @import("builtin").object_format,
- .Cross => blk: {
- if (self.isWindows() or self.isUefi()) {
- return .coff;
- } else if (self.isDarwin()) {
- return .macho;
- }
- if (self.isWasm()) {
- return .wasm;
- }
- return .elf;
- },
+ if (self.isWindows() or self.isUefi()) {
+ return .coff;
+ } else if (self.isDarwin()) {
+ return .macho;
}
+ if (self.isWasm()) {
+ return .wasm;
+ }
+ return .elf;
}
pub fn isMinGW(self: Target) bool {
@@ -921,56 +1166,53 @@ pub const Target = union(enum) {
}
pub fn isGnu(self: Target) bool {
- return switch (self.getAbi()) {
- .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true,
- else => false,
- };
+ return self.abi.isGnu();
}
pub fn isMusl(self: Target) bool {
- return switch (self.getAbi()) {
+ return switch (self.abi) {
.musl, .musleabi, .musleabihf => true,
else => false,
};
}
pub fn isDarwin(self: Target) bool {
- return switch (self.getOs()) {
+ return switch (self.os) {
.ios, .macosx, .watchos, .tvos => true,
else => false,
};
}
pub fn isWindows(self: Target) bool {
- return switch (self.getOs()) {
+ return switch (self.os) {
.windows => true,
else => false,
};
}
pub fn isLinux(self: Target) bool {
- return switch (self.getOs()) {
+ return switch (self.os) {
.linux => true,
else => false,
};
}
pub fn isAndroid(self: Target) bool {
- return switch (self.getAbi()) {
+ return switch (self.abi) {
.android => true,
else => false,
};
}
pub fn isDragonFlyBSD(self: Target) bool {
- return switch (self.getOs()) {
+ return switch (self.os) {
.dragonfly => true,
else => false,
};
}
pub fn isUefi(self: Target) bool {
- return switch (self.getOs()) {
+ return switch (self.os) {
.uefi => true,
else => false,
};
@@ -984,14 +1226,14 @@ pub const Target = union(enum) {
}
pub fn isFreeBSD(self: Target) bool {
- return switch (self.getOs()) {
+ return switch (self.os) {
.freebsd => true,
else => false,
};
}
pub fn isNetBSD(self: Target) bool {
- return switch (self.getOs()) {
+ return switch (self.os) {
.netbsd => true,
else => false,
};
@@ -1081,7 +1323,7 @@ pub const Target = union(enum) {
if (@as(@TagType(Target), self) == .Native) return .native;
// If the target OS matches the host OS, we can use QEMU to emulate a foreign architecture.
- if (self.getOs() == builtin.os) {
+ if (self.os == builtin.os) {
return switch (self.getArch()) {
.aarch64 => Executor{ .qemu = "qemu-aarch64" },
.aarch64_be => Executor{ .qemu = "qemu-aarch64_be" },
@@ -1112,7 +1354,7 @@ pub const Target = union(enum) {
}
}
- if (self.getOs() == .wasi) {
+ if (self.os == .wasi) {
switch (self.getArchPtrBitWidth()) {
32 => return Executor{ .wasmtime = "wasmtime" },
else => return .unavailable,
@@ -1129,7 +1371,7 @@ pub const Target = union(enum) {
};
pub fn getFloatAbi(self: Target) FloatAbi {
- return switch (self.getAbi()) {
+ return switch (self.abi) {
.gnueabihf,
.eabihf,
.musleabihf,
@@ -1145,7 +1387,7 @@ pub const Target = union(enum) {
=> return false,
else => {},
}
- switch (self.getOs()) {
+ switch (self.os) {
.freestanding,
.ios,
.tvos,
@@ -1200,7 +1442,7 @@ pub const Target = union(enum) {
return result.toOwnedSlice();
}
- switch (self.getOs()) {
+ switch (self.os) {
.freebsd => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.1"),
.netbsd => return mem.dupeZ(a, u8, "/libexec/ld.elf_so"),
.dragonfly => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.2"),
@@ -1233,7 +1475,7 @@ pub const Target = union(enum) {
.powerpc64, .powerpc64le => return mem.dupeZ(a, u8, "/lib64/ld64.so.2"),
.s390x => return mem.dupeZ(a, u8, "/lib64/ld64.so.1"),
.sparcv9 => return mem.dupeZ(a, u8, "/lib64/ld-linux.so.2"),
- .x86_64 => return mem.dupeZ(a, u8, switch (self.getAbi()) {
+ .x86_64 => return mem.dupeZ(a, u8, switch (self.abi) {
.gnux32 => "/libx32/ld-linux-x32.so.2",
else => "/lib64/ld-linux-x86-64.so.2",
}),
@@ -1292,10 +1534,10 @@ pub const Target = union(enum) {
test "Target.parse" {
{
- const target = (try Target.parse(.{
+ const target = try Target.parse(.{
.arch_os_abi = "x86_64-linux-gnu",
.cpu_features = "x86_64-sse-sse2-avx-cx8",
- })).Cross;
+ });
std.testing.expect(target.os == .linux);
std.testing.expect(target.abi == .gnu);
@@ -1307,10 +1549,10 @@ test "Target.parse" {
std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .fxsr));
}
{
- const target = (try Target.parse(.{
+ const target = try Target.parse(.{
.arch_os_abi = "arm-linux-musleabihf",
.cpu_features = "generic+v8a",
- })).Cross;
+ });
std.testing.expect(target.os == .linux);
std.testing.expect(target.abi == .musleabihf);
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 9b776da930..ceb232c79d 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -3963,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,
diff --git a/test/tests.zig b/test/tests.zig
index e9fdde2e4b..60008a2bc6 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -56,7 +56,7 @@ const test_targets = blk: {
.target = Target{
.Cross = CrossTarget{
.cpu = Target.Cpu.baseline(.x86_64),
- .os = .linux,
+ .os = Target.Os.defaultVersionRange(.linux),
.abi = .none,
},
},
@@ -65,7 +65,7 @@ const test_targets = blk: {
.target = Target{
.Cross = CrossTarget{
.cpu = Target.Cpu.baseline(.x86_64),
- .os = .linux,
+ .os = Target.Os.defaultVersionRange(.linux),
.abi = .gnu,
},
},
@@ -75,7 +75,7 @@ const test_targets = blk: {
.target = Target{
.Cross = CrossTarget{
.cpu = Target.Cpu.baseline(.x86_64),
- .os = .linux,
+ .os = Target.Os.defaultVersionRange(.linux),
.abi = .musl,
},
},
@@ -86,7 +86,7 @@ const test_targets = blk: {
.target = Target{
.Cross = CrossTarget{
.cpu = Target.Cpu.baseline(.i386),
- .os = .linux,
+ .os = Target.Os.defaultVersionRange(.linux),
.abi = .none,
},
},
@@ -95,7 +95,7 @@ const test_targets = blk: {
.target = Target{
.Cross = CrossTarget{
.cpu = Target.Cpu.baseline(.i386),
- .os = .linux,
+ .os = Target.Os.defaultVersionRange(.linux),
.abi = .musl,
},
},
@@ -106,7 +106,7 @@ const test_targets = blk: {
.target = Target{
.Cross = CrossTarget{
.cpu = Target.Cpu.baseline(.aarch64),
- .os = .linux,
+ .os = Target.Os.defaultVersionRange(.linux),
.abi = .none,
},
},
@@ -115,7 +115,7 @@ const test_targets = blk: {
.target = Target{
.Cross = CrossTarget{
.cpu = Target.Cpu.baseline(.aarch64),
- .os = .linux,
+ .os = Target.Os.defaultVersionRange(.linux),
.abi = .musl,
},
},
@@ -125,7 +125,7 @@ const test_targets = blk: {
.target = Target{
.Cross = CrossTarget{
.cpu = Target.Cpu.baseline(.aarch64),
- .os = .linux,
+ .os = Target.Os.defaultVersionRange(.linux),
.abi = .gnu,
},
},
@@ -158,7 +158,7 @@ const test_targets = blk: {
.target = Target{
.Cross = CrossTarget{
.cpu = Target.Cpu.baseline(.mipsel),
- .os = .linux,
+ .os = Target.Os.defaultVersionRange(.linux),
.abi = .none,
},
},
@@ -167,7 +167,7 @@ const test_targets = blk: {
.target = Target{
.Cross = CrossTarget{
.cpu = Target.Cpu.baseline(.mipsel),
- .os = .linux,
+ .os = Target.Os.defaultVersionRange(.linux),
.abi = .musl,
},
},
@@ -178,7 +178,7 @@ const test_targets = blk: {
.target = Target{
.Cross = CrossTarget{
.cpu = Target.Cpu.baseline(.x86_64),
- .os = .macosx,
+ .os = Target.Os.defaultVersionRange(.macosx),
.abi = .gnu,
},
},
@@ -190,7 +190,7 @@ const test_targets = blk: {
.target = Target{
.Cross = CrossTarget{
.cpu = Target.Cpu.baseline(.i386),
- .os = .windows,
+ .os = Target.Os.defaultVersionRange(.windows),
.abi = .msvc,
},
},
@@ -200,7 +200,7 @@ const test_targets = blk: {
.target = Target{
.Cross = CrossTarget{
.cpu = Target.Cpu.baseline(.x86_64),
- .os = .windows,
+ .os = Target.Os.defaultVersionRange(.windows),
.abi = .msvc,
},
},
@@ -210,7 +210,7 @@ const test_targets = blk: {
.target = Target{
.Cross = CrossTarget{
.cpu = Target.Cpu.baseline(.i386),
- .os = .windows,
+ .os = Target.Os.defaultVersionRange(.windows),
.abi = .gnu,
},
},
@@ -221,7 +221,7 @@ const test_targets = blk: {
.target = Target{
.Cross = CrossTarget{
.cpu = Target.Cpu.baseline(.x86_64),
- .os = .windows,
+ .os = Target.Os.defaultVersionRange(.windows),
.abi = .gnu,
},
},
From 4616af0ca459358ffa09ba27f9daa8527a38fd35 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 25 Feb 2020 01:52:27 -0500
Subject: [PATCH 04/62] introduce operating system version ranges as part of
the target
* re-introduce `std.build.Target` which is distinct from `std.Target`.
`std.build.Target` wraps `std.Target` so that it can be annotated as
"the native target" or an explicitly specified target.
* `std.Target.Os` is moved to `std.Target.Os.Tag`. The former is now a
struct which has the tag as well as version range information.
* `std.elf` gains some more ELF header constants.
* `std.Target.parse` gains the ability to parse operating system
version ranges as well as glibc version.
* Added `std.Target.isGnuLibC()`.
* self-hosted dynamic linker detection and glibc version detection.
This also adds the improved logic using `/usr/bin/env` rather than
invoking the system C compiler to find the dynamic linker when zig
is statically linked. Related: #2084
Note: this `/usr/bin/env` code is work-in-progress.
* `-target-glibc` CLI option is removed in favor of the new `-target`
syntax. Example: `-target x86_64-linux-gnu.2.27`
closes #1907
---
lib/std/build.zig | 40 +-
lib/std/build/run.zig | 2 +-
lib/std/builtin.zig | 4 +-
lib/std/c.zig | 25 +-
lib/std/c/linux.zig | 2 +-
lib/std/child_process.zig | 26 +-
lib/std/cstr.zig | 4 +-
lib/std/debug.zig | 24 +-
lib/std/dynamic_library.zig | 4 +-
lib/std/elf.zig | 25 +-
lib/std/event/channel.zig | 2 +-
lib/std/event/future.zig | 2 +-
lib/std/event/lock.zig | 2 +-
lib/std/event/loop.zig | 26 +-
lib/std/fs.zig | 46 +-
lib/std/fs/file.zig | 12 +-
lib/std/fs/get_app_data_dir.zig | 2 +-
lib/std/fs/path.zig | 38 +-
lib/std/fs/watch.zig | 8 +-
lib/std/heap.zig | 14 +-
lib/std/io.zig | 6 +-
lib/std/mutex.zig | 4 +-
lib/std/net.zig | 2 +-
lib/std/net/test.zig | 4 +-
lib/std/os.zig | 136 ++--
lib/std/os/bits.zig | 4 +-
lib/std/os/linux.zig | 2 +-
lib/std/os/test.zig | 16 +-
lib/std/packed_int_array.zig | 4 +-
lib/std/process.zig | 22 +-
lib/std/reset_event.zig | 6 +-
lib/std/special/c.zig | 8 +-
lib/std/special/compiler_rt.zig | 13 +-
.../special/compiler_rt/extendXfYf2_test.zig | 2 +-
lib/std/spinlock.zig | 2 +-
lib/std/start.zig | 16 +-
lib/std/target.zig | 597 +++++++++---------
lib/std/thread.zig | 20 +-
lib/std/time.zig | 18 +-
lib/std/zig/system.zig | 330 +++++++++-
src-self-hosted/c_int.zig | 2 +-
src-self-hosted/clang.zig | 2 +-
src-self-hosted/introspect.zig | 10 +-
src-self-hosted/libc_installation.zig | 112 +---
src-self-hosted/link.zig | 4 +-
src-self-hosted/main.zig | 6 +-
src-self-hosted/print_targets.zig | 12 +-
src-self-hosted/stage2.zig | 404 ++++++++----
src-self-hosted/util.zig | 22 -
src/codegen.cpp | 38 +-
src/error.cpp | 2 +
src/main.cpp | 29 +-
src/stage2.cpp | 8 -
src/stage2.h | 10 +-
test/stage1/behavior/asm.zig | 7 +-
test/stage1/behavior/byteswap.zig | 5 +-
.../namespace_depends_on_compile_var.zig | 8 +-
test/stage1/behavior/vector.zig | 3 +-
test/tests.zig | 2 +-
59 files changed, 1274 insertions(+), 932 deletions(-)
diff --git a/lib/std/build.zig b/lib/std/build.zig
index 29837d56d9..6c89e7b9d1 100644
--- a/lib/std/build.zig
+++ b/lib/std/build.zig
@@ -971,9 +971,9 @@ 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 buf: [1000]u8 = undefined;
+ var fba = std.heap.FixedBufferAllocator.init(&buf);
+ const builder = try Builder.create(&fba.allocator, "zig", "zig-cache", "zig-cache");
defer builder.destroy();
_ = builder.findProgram(&[_][]const u8{}, &[_][]const u8{}) catch null;
}
@@ -981,11 +981,37 @@ test "builder.findProgram compiles" {
/// Deprecated. Use `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;
+pub const CrossTarget = std.Target;
+
+/// Wraps `std.Target` so that it can be annotated as "the native target" or an explicitly specified target.
+pub const Target = union(enum) {
+ Native,
+ Cross: std.Target,
+
+ pub fn getTarget(self: Target) std.Target {
+ return switch (self) {
+ .Native => std.Target.current,
+ .Cross => |t| t,
+ };
+ }
+
+ pub fn getOs(self: Target) std.Target.Os.Tag {
+ return self.getTarget().os.tag;
+ }
+
+ pub fn getCpu(self: Target) std.Target.Cpu {
+ return self.getTarget().cpu;
+ }
+
+ pub fn getAbi(self: Target) std.Target.Abi {
+ return self.getTarget().abi;
+ }
+
+ pub fn getArch(self: Target) std.Target.Cpu.Arch {
+ return self.getCpu().arch;
+ }
+};
pub const Pkg = struct {
name: []const u8,
diff --git a/lib/std/build/run.zig b/lib/std/build/run.zig
index 75809bde03..eacf408ba9 100644
--- a/lib/std/build/run.zig
+++ b/lib/std/build/run.zig
@@ -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) {
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index 1bb8fd85ae..3204ce905e 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -411,7 +411,7 @@ pub const Version = struct {
}
};
- pub fn order(lhs: Version, rhs: version) std.math.Order {
+ 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;
@@ -504,7 +504,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();
diff --git a/lib/std/c.zig b/lib/std/c.zig
index f6c0e07dbd..9072d2c7cd 100644
--- a/lib/std/c.zig
+++ b/lib/std/c.zig
@@ -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;
}
};
};
diff --git a/lib/std/c/linux.zig b/lib/std/c/linux.zig
index 0f7abaaaa0..be32536d6f 100644
--- a/lib/std/c/linux.zig
+++ b/lib/std/c/linux.zig
@@ -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,
diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig
index bb8ed2e8a0..d5e914b286 100644
--- a/lib/std/child_process.zig
+++ b/lib/std/child_process.zig
@@ -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
diff --git a/lib/std/cstr.zig b/lib/std/cstr.zig
index 765e0a45cf..4057d4b62b 100644
--- a/lib/std/cstr.zig
+++ b/lib/std/cstr.zig
@@ -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",
};
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index 343df9bde0..558b7e0513 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -1,4 +1,5 @@
const std = @import("std.zig");
+const builtin = std.builtin;
const math = std.math;
const mem = std.mem;
const io = std.io;
@@ -11,7 +12,6 @@ const macho = std.macho;
const coff = std.coff;
const pdb = std.pdb;
const ArrayList = std.ArrayList;
-const builtin = @import("builtin");
const root = @import("root");
const maxInt = std.math.maxInt;
const File = std.fs.File;
@@ -101,7 +101,7 @@ pub fn detectTTYConfig() TTY.Config {
} else |_| {
if (stderr_file.supportsAnsiEscapeCodes()) {
return .escape_codes;
- } else if (builtin.os == .windows and stderr_file.isTty()) {
+ } else if (builtin.os.tag == .windows and stderr_file.isTty()) {
return .windows_api;
} else {
return .no_color;
@@ -155,7 +155,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void {
/// chopping off the irrelevant frames and shifting so that the returned addresses pointer
/// equals the passed in addresses pointer.
pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void {
- if (builtin.os == .windows) {
+ if (builtin.os.tag == .windows) {
const addrs = stack_trace.instruction_addresses;
const u32_addrs_len = @intCast(u32, addrs.len);
const first_addr = first_address orelse {
@@ -231,7 +231,7 @@ pub fn assert(ok: bool) void {
pub fn panic(comptime format: []const u8, args: var) noreturn {
@setCold(true);
// TODO: remove conditional once wasi / LLVM defines __builtin_return_address
- const first_trace_addr = if (builtin.os == .wasi) null else @returnAddress();
+ const first_trace_addr = if (builtin.os.tag == .wasi) null else @returnAddress();
panicExtra(null, first_trace_addr, format, args);
}
@@ -361,7 +361,7 @@ pub fn writeCurrentStackTrace(
tty_config: TTY.Config,
start_addr: ?usize,
) !void {
- if (builtin.os == .windows) {
+ if (builtin.os.tag == .windows) {
return writeCurrentStackTraceWindows(out_stream, debug_info, tty_config, start_addr);
}
var it = StackIterator.init(start_addr, null);
@@ -418,7 +418,7 @@ pub const TTY = struct {
.Dim => noasync out_stream.write(DIM) catch return,
.Reset => noasync out_stream.write(RESET) catch return,
},
- .windows_api => if (builtin.os == .windows) {
+ .windows_api => if (builtin.os.tag == .windows) {
const S = struct {
var attrs: windows.WORD = undefined;
var init_attrs = false;
@@ -617,7 +617,7 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo {
if (@hasDecl(root, "os") and @hasDecl(root.os, "debug") and @hasDecl(root.os.debug, "openSelfDebugInfo")) {
return noasync root.os.debug.openSelfDebugInfo(allocator);
}
- switch (builtin.os) {
+ switch (builtin.os.tag) {
.linux,
.freebsd,
.macosx,
@@ -1019,7 +1019,7 @@ pub const DebugInfo = struct {
pub fn getModuleForAddress(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
if (comptime std.Target.current.isDarwin())
return self.lookupModuleDyld(address)
- else if (builtin.os == .windows)
+ else if (builtin.os.tag == .windows)
return self.lookupModuleWin32(address)
else
return self.lookupModuleDl(address);
@@ -1242,7 +1242,7 @@ const SymbolInfo = struct {
}
};
-pub const ModuleDebugInfo = switch (builtin.os) {
+pub const ModuleDebugInfo = switch (builtin.os.tag) {
.macosx, .ios, .watchos, .tvos => struct {
base_address: usize,
mapped_memory: []const u8,
@@ -1602,7 +1602,7 @@ fn getDebugInfoAllocator() *mem.Allocator {
}
/// Whether or not the current target can print useful debug information when a segfault occurs.
-pub const have_segfault_handling_support = builtin.os == .linux or builtin.os == .windows;
+pub const have_segfault_handling_support = builtin.os.tag == .linux or builtin.os.tag == .windows;
pub const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler"))
root.enable_segfault_handler
else
@@ -1621,7 +1621,7 @@ pub fn attachSegfaultHandler() void {
if (!have_segfault_handling_support) {
@compileError("segfault handler not supported for this target");
}
- if (builtin.os == .windows) {
+ if (builtin.os.tag == .windows) {
windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
return;
}
@@ -1637,7 +1637,7 @@ pub fn attachSegfaultHandler() void {
}
fn resetSegfaultHandler() void {
- if (builtin.os == .windows) {
+ if (builtin.os.tag == .windows) {
if (windows_segfault_handle) |handle| {
assert(windows.kernel32.RemoveVectoredExceptionHandler(handle) != 0);
windows_segfault_handle = null;
diff --git a/lib/std/dynamic_library.zig b/lib/std/dynamic_library.zig
index 409dace20f..34f45894fb 100644
--- a/lib/std/dynamic_library.zig
+++ b/lib/std/dynamic_library.zig
@@ -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,
@@ -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",
diff --git a/lib/std/elf.zig b/lib/std/elf.zig
index 9e4c1ac5f6..007a01bb90 100644
--- a/lib/std/elf.zig
+++ b/lib/std/elf.zig
@@ -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),
@@ -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;
diff --git a/lib/std/event/channel.zig b/lib/std/event/channel.zig
index fd70f73aab..3c5b48d047 100644
--- a/lib/std/event/channel.zig
+++ b/lib/std/event/channel.zig
@@ -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{});
diff --git a/lib/std/event/future.zig b/lib/std/event/future.zig
index 492582da75..51a63e90ee 100644
--- a/lib/std/event/future.zig
+++ b/lib/std/event/future.zig
@@ -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;
diff --git a/lib/std/event/lock.zig b/lib/std/event/lock.zig
index e1b3495e5c..b9cbb5d95f 100644
--- a/lib/std/event/lock.zig
+++ b/lib/std/event/lock.zig
@@ -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();
diff --git a/lib/std/event/loop.zig b/lib/std/event/loop.zig
index 085e56fc15..80ba5a79b5 100644
--- a/lib/std/event/loop.zig
+++ b/lib/std/event/loop.zig
@@ -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 {
diff --git a/lib/std/fs.zig b/lib/std/fs.zig
index ecd2c2b750..5077c52cd9 100644
--- a/lib/std/fs.zig
+++ b/lib/std/fs.zig
@@ -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);
}
@@ -760,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);
}
@@ -770,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);
}
@@ -901,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);
}
@@ -919,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);
}
@@ -930,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 {
@@ -941,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 {
@@ -1083,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);
}
@@ -1340,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);
}
@@ -1350,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);
}
@@ -1381,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 };
@@ -1560,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);
@@ -1575,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.
}
@@ -1600,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 };
@@ -1642,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
diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig
index 9d0ffcfd4a..c243eeb62c 100644
--- a/lib/std/fs/file.zig
+++ b/lib/std/fs/file.zig
@@ -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,
};
@@ -83,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()) {
@@ -128,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;
@@ -138,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;
@@ -162,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);
@@ -209,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);
diff --git a/lib/std/fs/get_app_data_dir.zig b/lib/std/fs/get_app_data_dir.zig
index 35c0265435..31aab590d8 100644
--- a/lib/std/fs/get_app_data_dir.zig
+++ b/lib/std/fs/get_app_data_dir.zig
@@ -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(
diff --git a/lib/std/fs/path.zig b/lib/std/fs/path.zig
index 5d1c775629..35bc9b53b0 100644
--- a/lib/std/fs/path.zig
+++ b/lib/std/fs/path.zig
@@ -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);
diff --git a/lib/std/fs/watch.zig b/lib/std/fs/watch.zig
index 0ff8c47ecf..1eb5a97ff1 100644
--- a/lib/std/fs/watch.zig
+++ b/lib/std/fs/watch.zig
@@ -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),
diff --git a/lib/std/heap.zig b/lib/std/heap.zig
index 4295f1393d..65809e97b4 100644
--- a/lib/std/heap.zig
+++ b/lib/std/heap.zig
@@ -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();
diff --git a/lib/std/io.zig b/lib/std/io.zig
index 548f119b4f..6a2a080ef5 100644
--- a/lib/std/io.zig
+++ b/lib/std/io.zig
@@ -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;
}
diff --git a/lib/std/mutex.zig b/lib/std/mutex.zig
index 6954b2fb17..a57519cd14 100644
--- a/lib/std/mutex.zig
+++ b/lib/std/mutex.zig
@@ -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,
diff --git a/lib/std/net.zig b/lib/std/net.zig
index 898ba086be..b54803cd39 100644
--- a/lib/std/net.zig
+++ b/lib/std/net.zig
@@ -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);
diff --git a/lib/std/net/test.zig b/lib/std/net/test.zig
index 45d8b1cffd..4f3d955f30 100644
--- a/lib/std/net/test.zig
+++ b/lib/std/net/test.zig
@@ -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;
}
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 3b60a08cef..6e96413d78 100644
--- a/lib/std/os.zig
+++ b/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,
@@ -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);
}
@@ -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);
}
@@ -2811,7 +2811,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 +2823,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 +2840,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 +2852,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 +2868,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 +2880,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 +2896,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 +2908,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 +2957,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 +2967,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 +3121,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 +3144,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 +3222,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,7 +3294,7 @@ pub fn gethostname(name_buffer: *[HOST_NAME_MAX]u8) GetHostNameError![]u8 {
else => |err| return unexpectedErrno(err),
}
}
- if (builtin.os == .linux) {
+ if (builtin.os.tag == .linux) {
var uts: utsname = undefined;
switch (errno(system.uname(&uts))) {
0 => {
@@ -3611,7 +3611,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();
diff --git a/lib/std/os/bits.zig b/lib/std/os/bits.zig
index bab9ad0ae5..38f019d775 100644
--- a/lib/std/os/bits.zig
+++ b/lib/std/os/bits.zig
@@ -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"),
diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig
index d11f206482..30dba85e51 100644
--- a/lib/std/os/linux.zig
+++ b/lib/std/os/linux.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");
}
}
diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig
index 488a557ed6..197edd82c1 100644
--- a/lib/std/os/test.zig
+++ b/lib/std/os/test.zig
@@ -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);
diff --git a/lib/std/packed_int_array.zig b/lib/std/packed_int_array.zig
index 63b6fffa73..51be01315e 100644
--- a/lib/std/packed_int_array.zig
+++ b/lib/std/packed_int_array.zig
@@ -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,
}
diff --git a/lib/std/process.zig b/lib/std/process.zig
index 0dab8bb64b..118b5d9ab4 100644
--- a/lib/std/process.zig
+++ b/lib/std/process.zig
@@ -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) {
@@ -615,7 +615,7 @@ pub fn getSelfExeSharedLibPaths(allocator: *Allocator) error{OutOfMemory}![][:0]
.Dynamic => {},
}
const List = std.ArrayList([:0]u8);
- switch (builtin.os) {
+ switch (builtin.os.tag) {
.linux,
.freebsd,
.netbsd,
diff --git a/lib/std/reset_event.zig b/lib/std/reset_event.zig
index b31906c5f8..c28db809ca 100644
--- a/lib/std/reset_event.zig
+++ b/lib/std/reset_event.zig
@@ -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,
diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig
index 56ae3d0d8f..1f11fabca0 100644
--- a/lib/std/special/c.zig
+++ b/lib/std/special/c.zig
@@ -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,
};
@@ -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" });
}
}
diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig
index 8d49fdbd2a..3126e81b9d 100644
--- a/lib/std/special/compiler_rt.zig
+++ b/lib/std/special/compiler_rt.zig
@@ -1,11 +1,12 @@
-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_mingw = builtin.os.tag == .windows and is_gnu;
comptime {
const linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak;
@@ -180,7 +181,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 +251,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 +289,7 @@ comptime {
else => {},
}
} else {
- if (builtin.glibc_version != null) {
+ if (std.Target.current.isGnuLibC()) {
@export(__stack_chk_guard, .{ .name = "__stack_chk_guard", .linkage = linkage });
}
@export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage });
@@ -307,7 +308,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;
}
diff --git a/lib/std/special/compiler_rt/extendXfYf2_test.zig b/lib/std/special/compiler_rt/extendXfYf2_test.zig
index aa2faae901..e2664f6bae 100644
--- a/lib/std/special/compiler_rt/extendXfYf2_test.zig
+++ b/lib/std/special/compiler_rt/extendXfYf2_test.zig
@@ -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
diff --git a/lib/std/spinlock.zig b/lib/std/spinlock.zig
index 1a3239a95c..0af08e9a84 100644
--- a/lib/std/spinlock.zig
+++ b/lib/std/spinlock.zig
@@ -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),
}
diff --git a/lib/std/start.zig b/lib/std/start.zig
index b58b6e8144..b8e3e97f94 100644
--- a/lib/std/start.zig
+++ b/lib/std/start.zig
@@ -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;
diff --git a/lib/std/target.zig b/lib/std/target.zig
index 84056eae02..c9f8a247fe 100644
--- a/lib/std/target.zig
+++ b/lib/std/target.zig
@@ -11,143 +11,48 @@ pub const Target = struct {
os: Os,
abi: Abi,
- /// The version ranges here represent the minimum OS version to be supported
- /// and the maximum OS version to be supported. The default values represent
- /// the range that the Zig Standard Library bases its abstractions on.
- ///
- /// The minimum version of the range is the main setting to tweak for a target.
- /// Usually, the maximum target OS version will remain the default, which is
- /// the latest released version of the OS.
- ///
- /// To test at compile time if the target is guaranteed to support a given OS feature,
- /// one should check that the minimum version of the range is greater than or equal to
- /// the version the feature was introduced in.
- ///
- /// To test at compile time if the target certainly will not support a given OS feature,
- /// one should check that the maximum version of the range is less than the version the
- /// feature was introduced in.
- ///
- /// If neither of these cases apply, a runtime check should be used to determine if the
- /// target supports a given OS feature.
- ///
- /// Binaries built with a given maximum version will continue to function on newer operating system
- /// versions. However, such a binary may not take full advantage of the newer operating system APIs.
- pub const Os = union(enum) {
- freestanding,
- ananas,
- cloudabi,
- dragonfly,
- freebsd: Version.Range,
- fuchsia,
- ios,
- kfreebsd,
- linux: LinuxVersionRange,
- lv2,
- macosx: Version.Range,
- netbsd: Version.Range,
- openbsd: Version.Range,
- solaris,
- windows: WindowsVersion.Range,
- haiku,
- minix,
- rtems,
- nacl,
- cnk,
- aix,
- cuda,
- nvcl,
- amdhsa,
- ps4,
- elfiamcu,
- tvos,
- watchos,
- mesa3d,
- contiki,
- amdpal,
- hermit,
- hurd,
- wasi,
- emscripten,
- uefi,
- other,
+ pub const Os = struct {
+ tag: Tag,
+ version_range: VersionRange,
- /// See the documentation for `Os` for an explanation of the default version range.
- pub fn defaultVersionRange(tag: @TagType(Os)) Os {
- switch (tag) {
- .freestanding => return .freestanding,
- .ananas => return .ananas,
- .cloudabi => return .cloudabi,
- .dragonfly => return .dragonfly,
- .freebsd => return .{
- .freebsd = Version.Range{
- .min = .{ .major = 12, .minor = 0 },
- .max = .{ .major = 12, .minor = 1 },
- },
- },
- .fuchsia => return .fuchsia,
- .ios => return .ios,
- .kfreebsd => return .kfreebsd,
- .linux => return .{
- .linux = .{
- .range = .{
- .min = .{ .major = 3, .minor = 16 },
- .max = .{ .major = 5, .minor = 5, .patch = 5 },
- },
- .glibc = .{ .major = 2, .minor = 17 },
- },
- },
- .lv2 => return .lv2,
- .macosx => return .{
- .min = .{ .major = 10, .minor = 13 },
- .max = .{ .major = 10, .minor = 15, .patch = 3 },
- },
- .netbsd => return .{
- .min = .{ .major = 8, .minor = 0 },
- .max = .{ .major = 9, .minor = 0 },
- },
- .openbsd => return .{
- .min = .{ .major = 6, .minor = 6 },
- .max = .{ .major = 6, .minor = 6 },
- },
- solaris => return .solaris,
- windows => return .{
- .windows = .{
- .min = .win8_1,
- .max = .win10_19h1,
- },
- },
- haiku => return .haiku,
- minix => return .minix,
- rtems => return .rtems,
- nacl => return .nacl,
- cnk => return .cnk,
- aix => return .aix,
- cuda => return .cuda,
- nvcl => return .nvcl,
- amdhsa => return .amdhsa,
- ps4 => return .ps4,
- elfiamcu => return .elfiamcu,
- tvos => return .tvos,
- watchos => return .watchos,
- mesa3d => return .mesa3d,
- contiki => return .contiki,
- amdpal => return .amdpal,
- hermit => return .hermit,
- hurd => return .hurd,
- wasi => return .wasi,
- emscripten => return .emscripten,
- uefi => return .uefi,
- other => return .other,
- }
- }
-
- pub const LinuxVersionRange = struct {
- range: Version.Range,
- glibc: Version,
-
- pub fn includesVersion(self: LinuxVersionRange, ver: Version) bool {
- return self.range.includesVersion(ver);
- }
+ pub const Tag = enum {
+ freestanding,
+ ananas,
+ cloudabi,
+ dragonfly,
+ freebsd,
+ fuchsia,
+ ios,
+ kfreebsd,
+ linux,
+ lv2,
+ macosx,
+ netbsd,
+ openbsd,
+ solaris,
+ windows,
+ haiku,
+ minix,
+ rtems,
+ nacl,
+ cnk,
+ aix,
+ cuda,
+ nvcl,
+ amdhsa,
+ ps4,
+ elfiamcu,
+ tvos,
+ watchos,
+ mesa3d,
+ contiki,
+ amdpal,
+ hermit,
+ hurd,
+ wasi,
+ emscripten,
+ uefi,
+ other,
};
/// Based on NTDDI version constants from
@@ -178,29 +83,137 @@ pub const Target = struct {
return @enumToInt(ver) >= @enumToInt(self.min) and @enumToInt(ver) <= @enumToInt(self.max);
}
};
+ };
- pub fn nameToTag(name: []const u8) ?WindowsVersion {
- const info = @typeInfo(WindowsVersion);
- inline for (info.Enum.fields) |field| {
- if (mem.eql(u8, name, field.name)) {
- return @field(WindowsVersion, field.name);
- }
+ pub const LinuxVersionRange = struct {
+ range: Version.Range,
+ glibc: Version,
+
+ pub fn includesVersion(self: LinuxVersionRange, ver: Version) bool {
+ return self.range.includesVersion(ver);
+ }
+ };
+
+ /// The version ranges here represent the minimum OS version to be supported
+ /// and the maximum OS version to be supported. The default values represent
+ /// the range that the Zig Standard Library bases its abstractions on.
+ ///
+ /// The minimum version of the range is the main setting to tweak for a target.
+ /// Usually, the maximum target OS version will remain the default, which is
+ /// the latest released version of the OS.
+ ///
+ /// To test at compile time if the target is guaranteed to support a given OS feature,
+ /// one should check that the minimum version of the range is greater than or equal to
+ /// the version the feature was introduced in.
+ ///
+ /// To test at compile time if the target certainly will not support a given OS feature,
+ /// one should check that the maximum version of the range is less than the version the
+ /// feature was introduced in.
+ ///
+ /// If neither of these cases apply, a runtime check should be used to determine if the
+ /// target supports a given OS feature.
+ ///
+ /// Binaries built with a given maximum version will continue to function on newer operating system
+ /// versions. However, such a binary may not take full advantage of the newer operating system APIs.
+ pub const VersionRange = union {
+ none: void,
+ semver: Version.Range,
+ linux: LinuxVersionRange,
+ windows: WindowsVersion.Range,
+
+ /// The default `VersionRange` represents the range that the Zig Standard Library
+ /// bases its abstractions on.
+ pub fn default(tag: Tag) VersionRange {
+ 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 .{ .none = {} },
+
+ .freebsd => return .{
+ .semver = Version.Range{
+ .min = .{ .major = 12, .minor = 0 },
+ .max = .{ .major = 12, .minor = 1 },
+ },
+ },
+ .macosx => return .{
+ .semver = .{
+ .min = .{ .major = 10, .minor = 13 },
+ .max = .{ .major = 10, .minor = 15, .patch = 3 },
+ },
+ },
+ .netbsd => return .{
+ .semver = .{
+ .min = .{ .major = 8, .minor = 0 },
+ .max = .{ .major = 9, .minor = 0 },
+ },
+ },
+ .openbsd => return .{
+ .semver = .{
+ .min = .{ .major = 6, .minor = 6 },
+ .max = .{ .major = 6, .minor = 6 },
+ },
+ },
+
+ .linux => return .{
+ .linux = .{
+ .range = .{
+ .min = .{ .major = 3, .minor = 16 },
+ .max = .{ .major = 5, .minor = 5, .patch = 5 },
+ },
+ .glibc = .{ .major = 2, .minor = 17 },
+ },
+ },
+
+ .windows => return .{
+ .windows = .{
+ .min = .win8_1,
+ .max = .win10_19h1,
+ },
+ },
}
- return null;
}
};
pub fn parse(text: []const u8) !Os {
var it = mem.separate(text, ".");
const os_name = it.next().?;
- const tag = nameToTag(os_name) orelse return error.UnknownOperatingSystem;
+ const tag = std.meta.stringToEnum(Tag, os_name) orelse return error.UnknownOperatingSystem;
const version_text = it.rest();
const S = struct {
fn parseNone(s: []const u8) !void {
if (s.len != 0) return error.InvalidOperatingSystemVersion;
}
- fn parseSemVer(s: []const u8, default: Version.Range) !Version.Range {
- if (s.len == 0) return default;
+ fn parseSemVer(s: []const u8, d_range: Version.Range) !Version.Range {
+ if (s.len == 0) return d_range;
var range_it = mem.separate(s, "...");
const min_text = range_it.next().?;
@@ -212,7 +225,7 @@ pub const Target = struct {
const max_text = range_it.next() orelse return Version.Range{
.min = min_ver,
- .max = default.max,
+ .max = d_range.max,
};
const max_ver = Version.parse(max_text) catch |err| switch (err) {
error.Overflow => return error.InvalidOperatingSystemVersion,
@@ -222,79 +235,93 @@ pub const Target = struct {
return Version.Range{ .min = min_ver, .max = max_ver };
}
- fn parseWindows(s: []const u8, default: WindowsVersion.Range) !WindowsVersion.Range {
- if (s.len == 0) return default;
+ fn parseWindows(s: []const u8, d_range: WindowsVersion.Range) !WindowsVersion.Range {
+ if (s.len == 0) return d_range;
var range_it = mem.separate(s, "...");
const min_text = range_it.next().?;
- const min_ver = WindowsVersion.nameToTag(min_text) orelse
+ const min_ver = std.meta.stringToEnum(WindowsVersion, min_text) orelse
return error.InvalidOperatingSystemVersion;
const max_text = range_it.next() orelse return WindowsVersion.Range{
.min = min_ver,
- .max = default.max,
+ .max = d_range.max,
};
- const max_ver = WindowsVersion.nameToTag(max_text) orelse
+ const max_ver = std.meta.stringToEnum(WindowsVersion, max_text) orelse
return error.InvalidOperatingSystemVersion;
return WindowsVersion.Range{ .min = min_ver, .max = max_ver };
}
};
- const default = defaultVersionRange(tag);
+ const d_range = VersionRange.default(tag);
switch (tag) {
- .freestanding => return Os{ .freestanding = try S.parseNone(version_text) },
- .ananas => return Os{ .ananas = try S.parseNone(version_text) },
- .cloudabi => return Os{ .cloudabi = try S.parseNone(version_text) },
- .dragonfly => return Os{ .dragonfly = try S.parseNone(version_text) },
- .freebsd => return Os{ .freebsd = try S.parseSemVer(version_text, default.freebsd) },
- .fuchsia => return Os{ .fuchsia = try S.parseNone(version_text) },
- .ios => return Os{ .ios = try S.parseNone(version_text) },
- .kfreebsd => return Os{ .kfreebsd = try S.parseNone(version_text) },
+ .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 Os{
+ .tag = tag,
+ .version_range = .{ .none = try S.parseNone(version_text) },
+ },
+
+ .freebsd,
+ .macosx,
+ .netbsd,
+ .openbsd,
+ => return Os{
+ .tag = tag,
+ .version_range = .{ .semver = try S.parseSemVer(version_text, d_range.semver) },
+ },
+
.linux => return Os{
- .linux = .{
- .range = try S.parseSemVer(version_text, default.linux.range),
- .glibc = default.linux.glibc,
+ .tag = tag,
+ .version_range = .{
+ .linux = .{
+ .range = try S.parseSemVer(version_text, d_range.linux.range),
+ .glibc = d_range.linux.glibc,
+ },
},
},
- .lv2 => return Os{ .lv2 = try S.parseNone(version_text) },
- .macosx => return Os{ .macosx = try S.parseSemVer(version_text, default.macosx) },
- .netbsd => return Os{ .netbsd = try S.parseSemVer(version_text, default.netbsd) },
- .openbsd => return Os{ .openbsd = try S.parseSemVer(version_text, default.openbsd) },
- .solaris => return Os{ .solaris = try S.parseNone(version_text) },
- .windows => return Os{ .windows = try S.parseWindows(version_text, default.windows) },
- .haiku => return Os{ .haiku = try S.parseNone(version_text) },
- .minix => return Os{ .minix = try S.parseNone(version_text) },
- .rtems => return Os{ .rtems = try S.parseNone(version_text) },
- .nacl => return Os{ .nacl = try S.parseNone(version_text) },
- .cnk => return Os{ .cnk = try S.parseNone(version_text) },
- .aix => return Os{ .aix = try S.parseNone(version_text) },
- .cuda => return Os{ .cuda = try S.parseNone(version_text) },
- .nvcl => return Os{ .nvcl = try S.parseNone(version_text) },
- .amdhsa => return Os{ .amdhsa = try S.parseNone(version_text) },
- .ps4 => return Os{ .ps4 = try S.parseNone(version_text) },
- .elfiamcu => return Os{ .elfiamcu = try S.parseNone(version_text) },
- .tvos => return Os{ .tvos = try S.parseNone(version_text) },
- .watchos => return Os{ .watchos = try S.parseNone(version_text) },
- .mesa3d => return Os{ .mesa3d = try S.parseNone(version_text) },
- .contiki => return Os{ .contiki = try S.parseNone(version_text) },
- .amdpal => return Os{ .amdpal = try S.parseNone(version_text) },
- .hermit => return Os{ .hermit = try S.parseNone(version_text) },
- .hurd => return Os{ .hurd = try S.parseNone(version_text) },
- .wasi => return Os{ .wasi = try S.parseNone(version_text) },
- .emscripten => return Os{ .emscripten = try S.parseNone(version_text) },
- .uefi => return Os{ .uefi = try S.parseNone(version_text) },
- .other => return Os{ .other = try S.parseNone(version_text) },
+
+ .windows => return Os{
+ .tag = tag,
+ .version_range = .{ .windows = try S.parseWindows(version_text, d_range.windows) },
+ },
}
}
- pub fn nameToTag(name: []const u8) ?@TagType(Os) {
- const info = @typeInfo(Os);
- inline for (info.Union.fields) |field| {
- if (mem.eql(u8, name, field.name)) {
- return @field(Os, field.name);
- }
- }
- return null;
+ pub fn defaultVersionRange(tag: Tag) Os {
+ return .{
+ .tag = tag,
+ .version_range = VersionRange.default(tag),
+ };
}
};
@@ -339,11 +366,10 @@ pub const Target = struct {
macabi,
pub fn default(arch: Cpu.Arch, target_os: Os) Abi {
- switch (arch) {
- .wasm32, .wasm64 => return .musl,
- else => {},
+ if (arch.isWasm()) {
+ return .musl;
}
- switch (target_os) {
+ switch (target_os.tag) {
.freestanding,
.ananas,
.cloudabi,
@@ -388,40 +414,19 @@ pub const Target = struct {
}
}
- pub fn nameToTag(text: []const u8) ?Abi {
- const info = @typeInfo(Abi);
- inline for (info.Enum.fields) |field| {
- if (mem.eql(u8, text, field.name)) {
- return @field(Abi, field.name);
- }
- }
- return null;
- }
-
- pub fn parse(text: []const u8, os: *Os) !Abi {
- var it = mem.separate(text, ".");
- const tag = nameToTag(it.next().?) orelse return error.UnknownApplicationBinaryInterface;
- const version_text = it.rest();
- if (version_text.len != 0) {
- if (@as(@TagType(Os), os.*) == .linux and tag.isGnu()) {
- os.linux.glibc = Version.parse(version_text) catch |err| switch (err) {
- error.Overflow => return error.InvalidGlibcVersion,
- error.InvalidCharacter => return error.InvalidGlibcVersion,
- error.InvalidVersion => return error.InvalidGlibcVersion,
- };
- } else {
- return error.InvalidAbiVersion;
- }
- }
- return tag;
- }
-
pub fn isGnu(abi: Abi) bool {
return switch (abi) {
.gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true,
else => false,
};
}
+
+ pub fn isMusl(abi: Abi) bool {
+ return switch (abi) {
+ .musl, .musleabi, .musleabihf => true,
+ else => false,
+ };
+ }
};
pub const ObjectFormat = enum {
@@ -909,15 +914,15 @@ pub const Target = struct {
/// TODO add OS version ranges and glibc version
pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
return std.fmt.allocPrint(allocator, "{}-{}-{}", .{
- @tagName(self.getArch()),
- @tagName(self.os),
+ @tagName(self.cpu.arch),
+ @tagName(self.os.tag),
@tagName(self.abi),
});
}
/// Returned slice must be freed by the caller.
pub fn vcpkgTriplet(allocator: *mem.Allocator, target: Target, linkage: std.build.VcpkgLinkage) ![]const u8 {
- const arch = switch (target.getArch()) {
+ const arch = switch (target.cpu.arch) {
.i386 => "x86",
.x86_64 => "x64",
@@ -957,16 +962,16 @@ pub const Target = struct {
pub fn zigTripleNoSubArch(self: Target, allocator: *mem.Allocator) ![]u8 {
return std.fmt.allocPrint(allocator, "{}-{}-{}", .{
- @tagName(self.getArch()),
- @tagName(self.os),
+ @tagName(self.cpu.arch),
+ @tagName(self.os.tag),
@tagName(self.abi),
});
}
pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
return std.fmt.allocPrint(allocator, "{}-{}-{}", .{
- @tagName(self.getArch()),
- @tagName(self.os),
+ @tagName(self.cpu.arch),
+ @tagName(self.os.tag),
@tagName(self.abi),
});
}
@@ -1017,11 +1022,28 @@ pub const Target = struct {
diags.arch = arch;
const os_name = it.next() orelse return error.MissingOperatingSystem;
- var os = try Os.parse(os_name); // var because Abi.parse can update linux.glibc version
+ var os = try Os.parse(os_name);
diags.os = os;
- const abi_name = it.next();
- const abi = if (abi_name) |n| try Abi.parse(n, &os) else Abi.default(arch, os);
+ const opt_abi_text = it.next();
+ const abi = if (opt_abi_text) |abi_text| blk: {
+ var abi_it = mem.separate(abi_text, ".");
+ const abi = std.meta.stringToEnum(Abi, abi_it.next().?) orelse
+ return error.UnknownApplicationBinaryInterface;
+ const abi_ver_text = abi_it.rest();
+ if (abi_ver_text.len != 0) {
+ if (os.tag == .linux and abi.isGnu()) {
+ os.version_range.linux.glibc = Version.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;
+ }
+ }
+ break :blk abi;
+ } else Abi.default(arch, os);
diags.abi = abi;
if (it.next() != null) return error.UnexpectedExtraField;
@@ -1130,25 +1152,6 @@ pub const Target = struct {
}
}
- /// Deprecated; access the `os` field directly.
- pub fn getOs(self: Target) @TagType(Os) {
- return self.os;
- }
-
- /// Deprecated; access the `cpu` field directly.
- pub fn getCpu(self: Target) Cpu {
- return self.cpu;
- }
-
- /// Deprecated; access the `abi` field directly.
- pub fn getAbi(self: Target) Abi {
- return self.abi;
- }
-
- pub fn getArch(self: Target) Cpu.Arch {
- return self.cpu.arch;
- }
-
pub fn getObjectFormat(self: Target) ObjectFormat {
if (self.isWindows() or self.isUefi()) {
return .coff;
@@ -1170,28 +1173,25 @@ pub const Target = struct {
}
pub fn isMusl(self: Target) bool {
- return switch (self.abi) {
- .musl, .musleabi, .musleabihf => true,
- else => false,
- };
+ return self.abi.isMusl();
}
pub fn isDarwin(self: Target) bool {
- return switch (self.os) {
+ return switch (self.os.tag) {
.ios, .macosx, .watchos, .tvos => true,
else => false,
};
}
pub fn isWindows(self: Target) bool {
- return switch (self.os) {
+ return switch (self.os.tag) {
.windows => true,
else => false,
};
}
pub fn isLinux(self: Target) bool {
- return switch (self.os) {
+ return switch (self.os.tag) {
.linux => true,
else => false,
};
@@ -1205,40 +1205,41 @@ pub const Target = struct {
}
pub fn isDragonFlyBSD(self: Target) bool {
- return switch (self.os) {
+ return switch (self.os.tag) {
.dragonfly => true,
else => false,
};
}
pub fn isUefi(self: Target) bool {
- return switch (self.os) {
+ return switch (self.os.tag) {
.uefi => true,
else => false,
};
}
pub fn isWasm(self: Target) bool {
- return switch (self.getArch()) {
- .wasm32, .wasm64 => true,
- else => false,
- };
+ return self.cpu.arch.isWasm();
}
pub fn isFreeBSD(self: Target) bool {
- return switch (self.os) {
+ return switch (self.os.tag) {
.freebsd => true,
else => false,
};
}
pub fn isNetBSD(self: Target) bool {
- return switch (self.os) {
+ return switch (self.os.tag) {
.netbsd => true,
else => false,
};
}
+ pub fn isGnuLibC(self: Target) bool {
+ return self.os.tag == .linux and self.abi.isGnu();
+ }
+
pub fn wantSharedLibSymLinks(self: Target) bool {
return !self.isWindows();
}
@@ -1248,7 +1249,7 @@ pub const Target = struct {
}
pub fn getArchPtrBitWidth(self: Target) u32 {
- switch (self.getArch()) {
+ switch (self.cpu.arch) {
.avr,
.msp430,
=> return 16,
@@ -1323,8 +1324,8 @@ pub const Target = struct {
if (@as(@TagType(Target), self) == .Native) return .native;
// If the target OS matches the host OS, we can use QEMU to emulate a foreign architecture.
- if (self.os == builtin.os) {
- return switch (self.getArch()) {
+ if (self.os.tag == builtin.os.tag) {
+ return switch (self.cpu.arch) {
.aarch64 => Executor{ .qemu = "qemu-aarch64" },
.aarch64_be => Executor{ .qemu = "qemu-aarch64_be" },
.arm => Executor{ .qemu = "qemu-arm" },
@@ -1381,13 +1382,10 @@ pub const Target = struct {
}
pub fn hasDynamicLinker(self: Target) bool {
- switch (self.getArch()) {
- .wasm32,
- .wasm64,
- => return false,
- else => {},
+ if (self.cpu.arch.isWasm()) {
+ return false;
}
- switch (self.os) {
+ switch (self.os.tag) {
.freestanding,
.ios,
.tvos,
@@ -1424,7 +1422,7 @@ pub const Target = struct {
defer result.deinit();
var is_arm = false;
- switch (self.getArch()) {
+ switch (self.cpu.arch) {
.arm, .thumb => {
try result.append("arm");
is_arm = true;
@@ -1442,11 +1440,11 @@ pub const Target = struct {
return result.toOwnedSlice();
}
- switch (self.os) {
+ switch (self.os.tag) {
.freebsd => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.1"),
.netbsd => return mem.dupeZ(a, u8, "/libexec/ld.elf_so"),
.dragonfly => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.2"),
- .linux => switch (self.getArch()) {
+ .linux => switch (self.cpu.arch) {
.i386,
.sparc,
.sparcel,
@@ -1539,7 +1537,7 @@ test "Target.parse" {
.cpu_features = "x86_64-sse-sse2-avx-cx8",
});
- std.testing.expect(target.os == .linux);
+ 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));
@@ -1554,10 +1552,29 @@ test "Target.parse" {
.cpu_features = "generic+v8a",
});
- std.testing.expect(target.os == .linux);
+ 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 target = try Target.parse(.{
+ .arch_os_abi = "aarch64-linux.3.10...4.4.1-gnu.2.27",
+ .cpu_features = "generic+v8a",
+ });
+
+ std.testing.expect(target.cpu.arch == .aarch64);
+ std.testing.expect(target.os.tag == .linux);
+ std.testing.expect(target.os.version_range.linux.min.major == 3);
+ std.testing.expect(target.os.version_range.linux.min.minor == 10);
+ std.testing.expect(target.os.version_range.linux.min.patch == 0);
+ std.testing.expect(target.os.version_range.linux.max.major == 4);
+ std.testing.expect(target.os.version_range.linux.max.minor == 4);
+ std.testing.expect(target.os.version_range.linux.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);
+ }
}
diff --git a/lib/std/thread.zig b/lib/std/thread.zig
index fcc71ae5a5..55db9d1733 100644
--- a/lib/std/thread.zig
+++ b/lib/std/thread.zig
@@ -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 = builtin.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 (builtin.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 (builtin.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 (builtin.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 (builtin.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 (builtin.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 (builtin.os.tag == .windows) {
const WinThread = struct {
const OuterContext = struct {
thread: Thread,
@@ -309,7 +309,7 @@ pub const Thread = struct {
os.EINVAL => unreachable,
else => return os.unexpectedErrno(@intCast(usize, err)),
}
- } else if (builtin.os == .linux) {
+ } else if (builtin.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;
@@ -369,11 +369,11 @@ pub const Thread = struct {
};
pub fn cpuCount() CpuCountError!usize {
- if (builtin.os == .linux) {
+ if (builtin.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) {
+ if (builtin.os.tag == .windows) {
var system_info: windows.SYSTEM_INFO = undefined;
windows.kernel32.GetSystemInfo(&system_info);
return @intCast(usize, system_info.dwNumberOfProcessors);
diff --git a/lib/std/time.zig b/lib/std/time.zig
index 63d3ecce18..4112fb7bda 100644
--- a/lib/std/time.zig
+++ b/lib/std/time.zig
@@ -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()) {
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index 3931e362c6..5c9b71001b 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -1,11 +1,14 @@
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 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 +80,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 +164,326 @@ pub const NativePaths = struct {
try array.append(item);
}
};
+
+pub const NativeTargetInfo = struct {
+ target: Target,
+ dynamic_linker: ?[:0]u8,
+
+ pub const DetectError = error{
+ OutOfMemory,
+ FileSystem,
+ SystemResources,
+ SymLinkLoop,
+ ProcessFdQuotaExceeded,
+ SystemFdQuotaExceeded,
+ DeviceBusy,
+ };
+
+ /// Detects the native CPU model & features, operating system & version, and C ABI & dynamic linker.
+ /// On Linux, this is additionally responsible for detecting the native glibc version when applicable.
+ pub fn detect(allocator: *Allocator) DetectError!NativeTargetInfo {
+ const arch = Target.current.cpu.arch;
+ const os_tag = Target.current.os.tag;
+
+ // TODO Detect native CPU model & features. Until that is implemented we hard code baseline.
+ const cpu = Target.Cpu.baseline(arch);
+
+ // TODO Detect native operating system version. Until that is implemented we use the minimum version
+ // of the default range.
+ const os = Target.Os.defaultVersionRange(os_tag);
+
+ return detectAbiAndDynamicLinker(allocator, cpu, os);
+ }
+
+ /// Must be the same `Allocator` passed to `detect`.
+ pub fn deinit(self: *NativeTargetInfo, allocator: *Allocator) void {
+ if (self.dynamic_linker) |dl| allocator.free(dl);
+ self.* = undefined;
+ }
+
+ /// 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.
+ fn detectAbiAndDynamicLinker(
+ allocator: *Allocator,
+ cpu: Target.Cpu,
+ os: Target.Os,
+ ) DetectError!NativeTargetInfo {
+ if (!comptime Target.current.hasDynamicLinker()) {
+ return defaultAbiAndDynamicLinker(allocator, cpu, os);
+ }
+ // 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 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: {
+ 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;
+ };
+ 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 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 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.toSlice()) |ld_info| {
+ const standard_ld_basename = fs.path.basename(ld_info.ld_path);
+ 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()) {
+ 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;
+ }
+ }
+ }
+
+ return NativeTargetInfo{
+ .target = .{
+ .cpu = cpu,
+ .os = os_adjusted,
+ .abi = found_ld_info.abi,
+ },
+ .dynamic_linker = try mem.dupeZ(allocator, u8, found_ld_path),
+ };
+ }
+
+ // 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 abiAndDynamicLinkerFromUsrBinEnv(allocator, cpu, os) catch |err| switch (err) {
+ error.OutOfMemory => return error.OutOfMemory,
+ error.FileSystem => return error.FileSystem,
+ error.SystemResources => return error.SystemResources,
+ error.SymLinkLoop => return error.SymLinkLoop,
+ error.ProcessFdQuotaExceeded => return error.ProcessFdQuotaExceeded,
+ error.SystemFdQuotaExceeded => return error.SystemFdQuotaExceeded,
+ error.DeviceBusy => return error.DeviceBusy,
+
+ error.UnableToReadElfFile,
+ error.ElfNotADynamicExecutable,
+ error.InvalidElfProgramHeaders,
+ error.InvalidElfClass,
+ error.InvalidElfVersion,
+ error.InvalidElfEndian,
+ error.InvalidElfFile,
+ error.InvalidElfMagic,
+ error.UsrBinEnvNotAvailable,
+ error.Unexpected,
+ // Finally, we fall back on the standard path.
+ => defaultAbiAndDynamicLinker(allocator, cpu, os),
+ };
+ }
+
+ 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,
+ };
+ // 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,
+ };
+ }
+
+ fn abiAndDynamicLinkerFromUsrBinEnv(
+ allocator: *Allocator,
+ cpu: Target.Cpu,
+ os: Target.Os,
+ ) !NativeTargetInfo {
+ 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 => return error.UsrBinEnvNotAvailable,
+ error.NotDir => return error.UsrBinEnvNotAvailable,
+ error.AccessDenied => return error.UsrBinEnvNotAvailable,
+ error.NoDevice => return error.UsrBinEnvNotAvailable,
+ error.FileNotFound => return error.UsrBinEnvNotAvailable,
+ error.FileTooBig => return error.UsrBinEnvNotAvailable,
+
+ else => |e| return e,
+ };
+ var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined;
+ const hdr_bytes_len = try wrapRead(env_file.pread(&hdr_buf, 0));
+ if (hdr_bytes_len < @sizeOf(elf.Elf32_Ehdr)) return error.InvalidElfFile;
+ 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);
+ const shstrndx = elfInt(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx);
+
+ const ph_total_size = std.math.mul(u32, phentsize, phnum) catch |err| switch (err) {
+ error.Overflow => return error.InvalidElfProgramHeaders,
+ };
+ var ph_buf: [16 * @sizeOf(elf.Elf64_Phdr)]u8 align(@alignOf(elf.Elf64_Phdr)) = undefined;
+ 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 reserve = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr);
+ const read_byte_len = try wrapRead(env_file.pread(ph_buf[0 .. ph_buf.len - reserve], phoff));
+ if (read_byte_len < phentsize) return error.ElfNotADynamicExecutable;
+ var buf_i: usize = 0;
+ while (buf_i < read_byte_len and ph_i < phnum) : ({
+ ph_i += 1;
+ phoff += phentsize;
+ buf_i += phentsize;
+ }) {
+ const ph32 = @ptrCast(*elf.Elf32_Phdr, @alignCast(@alignOf(elf.Elf32_Phdr), &ph_buf[buf_i]));
+ const ph64 = @ptrCast(*elf.Elf64_Phdr, @alignCast(@alignOf(elf.Elf64_Phdr), &ph_buf[buf_i]));
+ const p_type = elfInt(is_64, need_bswap, ph32.p_type, ph64.p_type);
+ switch (p_type) {
+ elf.PT_INTERP => {
+ std.debug.warn("found PT_INTERP\n", .{});
+ },
+ elf.PT_DYNAMIC => {
+ std.debug.warn("found PT_DYNAMIC\n", .{});
+ },
+ else => continue,
+ }
+ }
+ }
+
+ return error.OutOfMemory; // TODO
+ }
+
+ fn wrapRead(res: std.os.ReadError!usize) !usize {
+ return res 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,
+ };
+ }
+
+ fn defaultAbiAndDynamicLinker(allocator: *Allocator, cpu: Target.Cpu, os: Target.Os) !NativeTargetInfo {
+ const target: Target = .{
+ .cpu = cpu,
+ .os = os,
+ .abi = Target.Abi.default(cpu.arch, os),
+ };
+ return @as(NativeTargetInfo, .{
+ .target = target,
+ .dynamic_linker = target.getStandardDynamicLinkerPath(allocator) catch |err| switch (err) {
+ error.OutOfMemory => return error.OutOfMemory,
+ error.UnknownDynamicLinkerPath, error.TargetHasNoDynamicLinker => null,
+ },
+ });
+ }
+};
+
+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;
+ }
+ }
+}
diff --git a/src-self-hosted/c_int.zig b/src-self-hosted/c_int.zig
index 2a840372b9..1ee27c7596 100644
--- a/src-self-hosted/c_int.zig
+++ b/src-self-hosted/c_int.zig
@@ -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,
diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig
index d2db306be8..bdaa8b86dc 100644
--- a/src-self-hosted/clang.zig
+++ b/src-self-hosted/clang.zig
@@ -1050,7 +1050,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;
diff --git a/src-self-hosted/introspect.zig b/src-self-hosted/introspect.zig
index 11838e7e63..c7f5690cc3 100644
--- a/src-self-hosted/introspect.zig
+++ b/src-self-hosted/introspect.zig
@@ -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" });
diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig
index 85740240ab..d617abb821 100644
--- a/src-self-hosted/libc_installation.zig
+++ b/src-self-hosted/libc_installation.zig
@@ -99,27 +99,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;
}
@@ -616,104 +616,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,
diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig
index 0a29da4778..1efa15574a 100644
--- a/src-self-hosted/link.zig
+++ b/src-self-hosted/link.zig
@@ -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,
diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig
index fbfd1e2642..264a896f46 100644
--- a/src-self-hosted/main.zig
+++ b/src-self-hosted/main.zig
@@ -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")) {
diff --git a/src-self-hosted/print_targets.zig b/src-self-hosted/print_targets.zig
index 16f1891164..be024a2a04 100644
--- a/src-self-hosted/print_targets.zig
+++ b/src-self-hosted/print_targets.zig
@@ -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();
diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig
index dacdb86bcd..7f0f35abe0 100644
--- a/src-self-hosted/stage2.zig
+++ b/src-self-hosted/stage2.zig
@@ -110,6 +110,8 @@ const Error = extern enum {
WindowsSdkNotFound,
UnknownDynamicLinkerPath,
TargetHasNoDynamicLinker,
+ InvalidAbiVersion,
+ InvalidOperatingSystemVersion,
};
const FILE = std.c.FILE;
@@ -633,11 +635,11 @@ 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: {
+ target.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);
+ break :blk try detectNativeCpuWithLLVM(target.cpu.arch, llvm_cpu_name, llvm_cpu_features);
};
return @import("print_targets.zig").cmdTargets(
std.heap.c_allocator,
@@ -662,6 +664,14 @@ export fn stage2_target_parse(
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;
}
@@ -671,108 +681,48 @@ fn stage2TargetParse(
zig_triple_oz: ?[*:0]const u8,
mcpu_oz: ?[*:0]const u8,
) !void {
- const target: Target = if (zig_triple_oz) |zig_triple_z| blk: {
+ const target: std.build.Target = 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(.{
- .arch_os_abi = zig_triple,
- .cpu_features = mcpu,
- .diagnostics = &diags,
- }) catch |err| switch (err) {
- error.UnknownCpu => {
- 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);
+ break :blk std.build.Target{
+ .Cross = Target.parse(.{
+ .arch_os_abi = zig_triple,
+ .cpu_features = mcpu,
+ .diagnostics = &diags,
+ }) catch |err| switch (err) {
+ error.UnknownCpu => {
+ 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);
+ },
+ else => |e| return e,
},
- 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);
- },
- else => |e| return e,
};
- } else Target.Native;
+ } else std.build.Target.Native;
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,
@@ -952,10 +902,13 @@ const Stage2Target = extern struct {
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 {
+ dynamic_linker: ?[*:0]const u8,
+
+ fn toTarget(in_target: Stage2Target) std.build.Target {
if (in_target.is_native) return .Native;
const in_arch = in_target.arch - 1; // skip over ZigLLVM_UnknownArch
@@ -965,39 +918,244 @@ 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) {
+ fn fromTarget(self: *Stage2Target, build_target: std.build.Target) !void {
+ const allocator = std.heap.c_allocator;
+ var dynamic_linker: ?[*:0]u8 = null;
+ const target = switch (build_target) {
.Native => blk: {
- // TODO self-host CPU model and feature detection instead of relying on LLVM
+ const info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator);
+ if (info.dynamic_linker) |dl| {
+ dynamic_linker = dl.ptr;
+ }
+
+ // TODO we want to just use 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();
- break :blk try detectNativeCpuWithLLVM(target.getArch(), llvm_cpu_name, llvm_cpu_features);
+ const arch = std.Target.current.cpu.arch;
+ var t = info.target;
+ t.cpu = try detectNativeCpuWithLLVM(arch, llvm_cpu_name, llvm_cpu_features);
+ break :blk t;
},
- .Cross => target.getCpu(),
+ .Cross => |t| t,
};
+
+ 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(
+ \\.semver = .{{
+ \\ .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_version = if (target.isGnuLibC()) blk: {
+ const stage1_glibc = try std.heap.c_allocator.create(Stage2GLibCVersion);
+ 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 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 = build_target == .Native,
+ .glibc_version = glibc_version,
+ .dynamic_linker = dynamic_linker,
};
- try initStage1TargetCpuFeatures(self, cpu);
}
};
+fn enumInt(comptime Enum: type, int: c_int) Enum {
+ return @intToEnum(Enum, @intCast(@TagType(Enum), int));
+}
+
// ABI warning
const Stage2GLibCVersion = extern struct {
major: u32,
@@ -1005,26 +1163,6 @@ const Stage2GLibCVersion = extern struct {
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));
-}
-
// ABI warning
const Stage2NativePaths = extern struct {
include_dirs_ptr: [*][*:0]u8,
diff --git a/src-self-hosted/util.zig b/src-self-hosted/util.zig
index 04c5420d26..2a7bf4d9cc 100644
--- a/src-self-hosted/util.zig
+++ b/src-self-hosted/util.zig
@@ -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;
-}
diff --git a/src/codegen.cpp b/src/codegen.cpp
index ee3e05a801..15122d5e11 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -4483,7 +4483,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
@@ -8543,25 +8543,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));
@@ -8867,8 +8866,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)
@@ -8876,16 +8873,9 @@ static void detect_dynamic_linker(CodeGen *g) {
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);
+ if (g->zig_target->dynamic_linker != nullptr) {
+ g->dynamic_linker_path = buf_create_from_str(g->zig_target->dynamic_linker);
}
- 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) {
diff --git a/src/error.cpp b/src/error.cpp
index 730c6e7193..2e92a98217 100644
--- a/src/error.cpp
+++ b/src/error.cpp
@@ -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)";
}
diff --git a/src/main.cpp b/src/main.cpp
index a4ab719123..11612402ee 100644
--- a/src/main.cpp
+++ b/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] -- see the targets command\n"
- " -target-glibc [version] target a specific glibc version (default: 2.17)\n"
+ " -target [name] -- 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"
@@ -419,7 +418,6 @@ static int main0(int argc, char **argv) {
const char *mios_version_min = nullptr;
const char *linker_script = nullptr;
Buf *version_script = nullptr;
- const char *target_glibc = nullptr;
ZigList rpath_list = {0};
bool each_lib_rpath = false;
ZigList objects = {0};
@@ -853,8 +851,6 @@ static int main0(int argc, char **argv) {
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) {
@@ -982,29 +978,6 @@ static int main0(int argc, char **argv) {
"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();
-
- 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);
diff --git a/src/stage2.cpp b/src/stage2.cpp
index 736f11622e..2023b45aaf 100644
--- a/src/stage2.cpp
+++ b/src/stage2.cpp
@@ -100,13 +100,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,7 +146,6 @@ 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";
}
@@ -186,11 +183,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;
diff --git a/src/stage2.h b/src/stage2.h
index e6db241e88..96222e3138 100644
--- a/src/stage2.h
+++ b/src/stage2.h
@@ -103,6 +103,8 @@ enum Error {
ErrorWindowsSdkNotFound,
ErrorUnknownDynamicLinkerPath,
ErrorTargetHasNoDynamicLinker,
+ ErrorInvalidAbiVersion,
+ ErrorInvalidOperatingSystemVersion,
};
// ABI warning
@@ -290,14 +292,12 @@ struct ZigTarget {
const char *llvm_cpu_name;
const char *llvm_cpu_features;
- const char *builtin_str;
+ const char *cpu_builtin_str;
const char *cache_hash;
+ const char *os_builtin_str;
+ const char *dynamic_linker;
};
-// ABI warning
-ZIG_EXTERN_C enum Error stage2_detect_dynamic_linker(const struct ZigTarget *target,
- char **out_ptr, size_t *out_len);
-
// ABI warning
ZIG_EXTERN_C enum Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu);
diff --git a/test/stage1/behavior/asm.zig b/test/stage1/behavior/asm.zig
index d1404c6f45..170ad3325d 100644
--- a/test/stage1/behavior/asm.zig
+++ b/test/stage1/behavior/asm.zig
@@ -1,9 +1,10 @@
const std = @import("std");
-const config = @import("builtin");
const expect = std.testing.expect;
+const is_x86_64_linux = std.Target.current.cpu.arch == .x86_64 and std.Target.current.os.tag == .linux;
+
comptime {
- if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
+ if (is_x86_64_linux) {
asm (
\\.globl this_is_my_alias;
\\.type this_is_my_alias, @function;
@@ -13,7 +14,7 @@ comptime {
}
test "module level assembly" {
- if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
+ if (is_x86_64_linux) {
expect(this_is_my_alias() == 1234);
}
}
diff --git a/test/stage1/behavior/byteswap.zig b/test/stage1/behavior/byteswap.zig
index c799ba4849..d6e07e7a56 100644
--- a/test/stage1/behavior/byteswap.zig
+++ b/test/stage1/behavior/byteswap.zig
@@ -1,6 +1,5 @@
const std = @import("std");
const expect = std.testing.expect;
-const builtin = @import("builtin");
test "@byteSwap integers" {
const ByteSwapIntTest = struct {
@@ -41,10 +40,10 @@ test "@byteSwap integers" {
test "@byteSwap vectors" {
// https://github.com/ziglang/zig/issues/3563
- if (builtin.os == .dragonfly) return error.SkipZigTest;
+ if (std.Target.current.os.tag == .dragonfly) return error.SkipZigTest;
// https://github.com/ziglang/zig/issues/3317
- if (builtin.arch == .mipsel) return error.SkipZigTest;
+ if (std.Target.current.cpu.arch == .mipsel) return error.SkipZigTest;
const ByteSwapVectorTest = struct {
fn run() void {
diff --git a/test/stage1/behavior/namespace_depends_on_compile_var.zig b/test/stage1/behavior/namespace_depends_on_compile_var.zig
index 4c4fc4eefe..8c5c19d733 100644
--- a/test/stage1/behavior/namespace_depends_on_compile_var.zig
+++ b/test/stage1/behavior/namespace_depends_on_compile_var.zig
@@ -1,5 +1,5 @@
-const builtin = @import("builtin");
-const expect = @import("std").testing.expect;
+const std = @import("std");
+const expect = std.testing.expect;
test "namespace depends on compile var" {
if (some_namespace.a_bool) {
@@ -8,7 +8,7 @@ test "namespace depends on compile var" {
expect(!some_namespace.a_bool);
}
}
-const some_namespace = switch (builtin.os) {
- builtin.Os.linux => @import("namespace_depends_on_compile_var/a.zig"),
+const some_namespace = switch (std.builtin.os.tag) {
+ .linux => @import("namespace_depends_on_compile_var/a.zig"),
else => @import("namespace_depends_on_compile_var/b.zig"),
};
diff --git a/test/stage1/behavior/vector.zig b/test/stage1/behavior/vector.zig
index e89399c5e2..01e5ac1fb8 100644
--- a/test/stage1/behavior/vector.zig
+++ b/test/stage1/behavior/vector.zig
@@ -2,7 +2,6 @@ const std = @import("std");
const mem = std.mem;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
-const builtin = @import("builtin");
test "implicit cast vector to array - bool" {
const S = struct {
@@ -114,7 +113,7 @@ test "array to vector" {
test "vector casts of sizes not divisable by 8" {
// https://github.com/ziglang/zig/issues/3563
- if (builtin.os == .dragonfly) return error.SkipZigTest;
+ if (std.Target.current.os.tag == .dragonfly) return error.SkipZigTest;
const S = struct {
fn doTheTest() void {
diff --git a/test/tests.zig b/test/tests.zig
index 60008a2bc6..c088aafc5f 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -31,7 +31,7 @@ pub const RunTranslatedCContext = @import("src/run_translated_c.zig").RunTransla
pub const CompareOutputContext = @import("src/compare_output.zig").CompareOutputContext;
const TestTarget = struct {
- target: Target = .Native,
+ target: build.Target = .Native,
mode: builtin.Mode = .Debug,
link_libc: bool = false,
single_threaded: bool = false,
From d4f375c46be2e509ee9161b0577d8a25d6620b3e Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 25 Feb 2020 02:52:49 -0500
Subject: [PATCH 05/62] stage1: remove get_self_libc_path
and glibc_detect_native_version
---
src/compiler.cpp | 25 -------------------------
src/compiler.hpp | 1 -
src/glibc.cpp | 37 -------------------------------------
src/glibc.hpp | 3 ---
4 files changed, 66 deletions(-)
diff --git a/src/compiler.cpp b/src/compiler.cpp
index 31bac4ee24..cddecc2025 100644
--- a/src/compiler.cpp
+++ b/src/compiler.cpp
@@ -4,31 +4,6 @@
#include
-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 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;
diff --git a/src/compiler.hpp b/src/compiler.hpp
index 4a1699b782..47841af5dc 100644
--- a/src/compiler.hpp
+++ b/src/compiler.hpp
@@ -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);
diff --git a/src/glibc.cpp b/src/glibc.cpp
index 849aac6c77..91e2f9dfc1 100644
--- a/src/glibc.cpp
+++ b/src/glibc.cpp
@@ -362,43 +362,6 @@ bool eql_glibc_target(const ZigTarget *a, const ZigTarget *b) {
a->abi == b->abi;
}
-#ifdef ZIG_OS_LINUX
-#include
-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);
}
diff --git a/src/glibc.hpp b/src/glibc.hpp
index 42c2099371..8e4c7888ad 100644
--- a/src/glibc.hpp
+++ b/src/glibc.hpp
@@ -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);
From 87b9e744dda465ecf7663e2463066ea26a44e63a Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 25 Feb 2020 03:43:21 -0500
Subject: [PATCH 06/62] update std lib to new Target API
---
lib/std/build.zig | 81 ++++++++++-
lib/std/build/translate_c.zig | 4 +-
lib/std/fmt/parse_float.zig | 2 +-
lib/std/io/test.zig | 2 +-
lib/std/math/fabs.zig | 2 +-
lib/std/math/isinf.zig | 6 +-
lib/std/math/isnan.zig | 2 +-
lib/std/os.zig | 4 +-
lib/std/special/compiler_rt/addXf3_test.zig | 4 +-
lib/std/special/compiler_rt/fixtfdi_test.zig | 2 +-
lib/std/special/compiler_rt/fixtfsi_test.zig | 2 +-
lib/std/special/compiler_rt/fixtfti_test.zig | 2 +-
.../special/compiler_rt/fixunstfdi_test.zig | 2 +-
.../special/compiler_rt/fixunstfsi_test.zig | 2 +-
.../special/compiler_rt/fixunstfti_test.zig | 2 +-
.../special/compiler_rt/floattitf_test.zig | 2 +-
.../special/compiler_rt/floatuntitf_test.zig | 2 +-
lib/std/special/compiler_rt/mulXf3_test.zig | 2 +-
.../special/compiler_rt/truncXfYf2_test.zig | 4 +-
lib/std/target.zig | 118 +++++-----------
src-self-hosted/libc_installation.zig | 14 +-
test/assemble_and_link.zig | 4 +-
test/compile_errors.zig | 11 +-
test/src/translate_c.zig | 4 +-
test/stack_traces.zig | 77 ++++++-----
test/stage1/behavior/math.zig | 20 +--
test/standalone.zig | 4 +-
test/tests.zig | 127 +++++++++---------
test/translate_c.zig | 34 ++---
29 files changed, 281 insertions(+), 261 deletions(-)
diff --git a/lib/std/build.zig b/lib/std/build.zig
index 6c89e7b9d1..25f7d536b1 100644
--- a/lib/std/build.zig
+++ b/lib/std/build.zig
@@ -971,7 +971,7 @@ pub const Builder = struct {
};
test "builder.findProgram compiles" {
- var buf: [1000]u8 = undefined;
+ var buf: [50000]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buf);
const builder = try Builder.create(&fba.allocator, "zig", "zig-cache", "zig-cache");
defer builder.destroy();
@@ -1011,6 +1011,77 @@ pub const Target = union(enum) {
pub fn getArch(self: Target) std.Target.Cpu.Arch {
return self.getCpu().arch;
}
+
+ pub fn isFreeBSD(self: Target) bool {
+ return self.getTarget().os.tag == .freebsd;
+ }
+
+ pub fn isDarwin(self: Target) bool {
+ return self.getTarget().os.tag.isDarwin();
+ }
+
+ pub fn isNetBSD(self: Target) bool {
+ return self.getTarget().os.tag == .netbsd;
+ }
+
+ pub fn isUefi(self: Target) bool {
+ return self.getTarget().os.tag == .uefi;
+ }
+
+ pub fn isDragonFlyBSD(self: Target) bool {
+ return self.getTarget().os.tag == .dragonfly;
+ }
+
+ pub fn isLinux(self: Target) bool {
+ return self.getTarget().os.tag == .linux;
+ }
+
+ pub fn isWindows(self: Target) bool {
+ return self.getTarget().os.tag == .windows;
+ }
+
+ pub fn oFileExt(self: Target) []const u8 {
+ return self.getTarget().oFileExt();
+ }
+
+ pub fn exeFileExt(self: Target) []const u8 {
+ return self.getTarget().exeFileExt();
+ }
+
+ pub fn staticLibSuffix(self: Target) []const u8 {
+ return self.getTarget().staticLibSuffix();
+ }
+
+ pub fn libPrefix(self: Target) []const u8 {
+ return self.getTarget().libPrefix();
+ }
+
+ pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
+ return self.getTarget().zigTriple(allocator);
+ }
+
+ pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
+ return self.getTarget().linuxTriple(allocator);
+ }
+
+ pub fn wantSharedLibSymLinks(self: Target) bool {
+ return self.getTarget().wantSharedLibSymLinks();
+ }
+
+ pub fn vcpkgTriplet(self: Target, allocator: *mem.Allocator, linkage: std.build.VcpkgLinkage) ![]const u8 {
+ return self.getTarget().vcpkgTriplet(allocator, linkage);
+ }
+
+ pub fn getExternalExecutor(self: Target) std.Target.Executor {
+ switch (self) {
+ .Native => return .native,
+ .Cross => |t| return t.getExternalExecutor(),
+ }
+ }
+
+ pub fn isGnuLibC(self: Target) bool {
+ return self.getTarget().isGnuLibC();
+ }
};
pub const Pkg = struct {
@@ -1718,7 +1789,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" });
@@ -1944,7 +2015,7 @@ pub const LibExeObjStep = struct {
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) {
+ if (cross.cpu.model != std.Target.Cpu.baseline(self.target.getArch()).model) {
try zig_args.append("-mcpu");
try zig_args.append(cross.cpu.model.name);
}
@@ -1953,7 +2024,7 @@ pub const LibExeObjStep = struct {
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 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) {
@@ -2001,7 +2072,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
diff --git a/lib/std/build/translate_c.zig b/lib/std/build/translate_c.zig
index 3d1bdad677..90e95be5e1 100644
--- a/lib/std/build/translate_c.zig
+++ b/lib/std/build/translate_c.zig
@@ -14,7 +14,7 @@ pub const TranslateCStep = struct {
source: build.FileSource,
output_dir: ?[]const u8,
out_basename: []const u8,
- target: std.Target = .Native,
+ target: build.Target = .Native,
pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep {
const self = builder.allocator.create(TranslateCStep) catch unreachable;
@@ -39,7 +39,7 @@ pub const TranslateCStep = struct {
) catch unreachable;
}
- pub fn setTarget(self: *TranslateCStep, target: std.Target) void {
+ pub fn setTarget(self: *TranslateCStep, target: build.Target) void {
self.target = target;
}
diff --git a/lib/std/fmt/parse_float.zig b/lib/std/fmt/parse_float.zig
index aa6e414336..c62d614a6f 100644
--- a/lib/std/fmt/parse_float.zig
+++ b/lib/std/fmt/parse_float.zig
@@ -382,7 +382,7 @@ pub fn parseFloat(comptime T: type, s: []const u8) !T {
}
test "fmt.parseFloat" {
- if (std.Target.current.isWindows()) {
+ if (std.Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
diff --git a/lib/std/io/test.zig b/lib/std/io/test.zig
index dae8940016..f1840b49e3 100644
--- a/lib/std/io/test.zig
+++ b/lib/std/io/test.zig
@@ -544,7 +544,7 @@ fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime packing:
}
test "Serializer/Deserializer generic" {
- if (std.Target.current.isWindows()) {
+ if (std.Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
diff --git a/lib/std/math/fabs.zig b/lib/std/math/fabs.zig
index 61692283e6..2635962fcc 100644
--- a/lib/std/math/fabs.zig
+++ b/lib/std/math/fabs.zig
@@ -95,7 +95,7 @@ test "math.fabs64.special" {
}
test "math.fabs128.special" {
- if (std.Target.current.isWindows()) {
+ if (std.Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
diff --git a/lib/std/math/isinf.zig b/lib/std/math/isinf.zig
index eeac61915c..c51747fd12 100644
--- a/lib/std/math/isinf.zig
+++ b/lib/std/math/isinf.zig
@@ -74,7 +74,7 @@ pub fn isNegativeInf(x: var) bool {
}
test "math.isInf" {
- if (std.Target.current.isWindows()) {
+ if (std.Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
@@ -97,7 +97,7 @@ test "math.isInf" {
}
test "math.isPositiveInf" {
- if (std.Target.current.isWindows()) {
+ if (std.Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
@@ -120,7 +120,7 @@ test "math.isPositiveInf" {
}
test "math.isNegativeInf" {
- if (std.Target.current.isWindows()) {
+ if (std.Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
diff --git a/lib/std/math/isnan.zig b/lib/std/math/isnan.zig
index 4b7e69490a..2879c44502 100644
--- a/lib/std/math/isnan.zig
+++ b/lib/std/math/isnan.zig
@@ -16,7 +16,7 @@ pub fn isSignalNan(x: var) bool {
}
test "math.isNan" {
- if (std.Target.current.isWindows()) {
+ if (std.Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 6e96413d78..9f349e7dc4 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -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);
diff --git a/lib/std/special/compiler_rt/addXf3_test.zig b/lib/std/special/compiler_rt/addXf3_test.zig
index 402bb5a43c..d7e175045c 100644
--- a/lib/std/special/compiler_rt/addXf3_test.zig
+++ b/lib/std/special/compiler_rt/addXf3_test.zig
@@ -31,7 +31,7 @@ fn test__addtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) void {
}
test "addtf3" {
- if (@import("std").Target.current.isWindows()) {
+ if (@import("std").Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
@@ -75,7 +75,7 @@ fn test__subtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) void {
}
test "subtf3" {
- if (@import("std").Target.current.isWindows()) {
+ if (@import("std").Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
diff --git a/lib/std/special/compiler_rt/fixtfdi_test.zig b/lib/std/special/compiler_rt/fixtfdi_test.zig
index 4c43c90550..cb4b94c5cd 100644
--- a/lib/std/special/compiler_rt/fixtfdi_test.zig
+++ b/lib/std/special/compiler_rt/fixtfdi_test.zig
@@ -11,7 +11,7 @@ fn test__fixtfdi(a: f128, expected: i64) void {
}
test "fixtfdi" {
- if (@import("std").Target.current.isWindows()) {
+ if (@import("std").Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
diff --git a/lib/std/special/compiler_rt/fixtfsi_test.zig b/lib/std/special/compiler_rt/fixtfsi_test.zig
index 4eabd0c594..96bb151e80 100644
--- a/lib/std/special/compiler_rt/fixtfsi_test.zig
+++ b/lib/std/special/compiler_rt/fixtfsi_test.zig
@@ -11,7 +11,7 @@ fn test__fixtfsi(a: f128, expected: i32) void {
}
test "fixtfsi" {
- if (@import("std").Target.current.isWindows()) {
+ if (@import("std").Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
diff --git a/lib/std/special/compiler_rt/fixtfti_test.zig b/lib/std/special/compiler_rt/fixtfti_test.zig
index acda2f162b..73cc0596e7 100644
--- a/lib/std/special/compiler_rt/fixtfti_test.zig
+++ b/lib/std/special/compiler_rt/fixtfti_test.zig
@@ -11,7 +11,7 @@ fn test__fixtfti(a: f128, expected: i128) void {
}
test "fixtfti" {
- if (@import("std").Target.current.isWindows()) {
+ if (@import("std").Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
diff --git a/lib/std/special/compiler_rt/fixunstfdi_test.zig b/lib/std/special/compiler_rt/fixunstfdi_test.zig
index 154fffe18a..02cef2f700 100644
--- a/lib/std/special/compiler_rt/fixunstfdi_test.zig
+++ b/lib/std/special/compiler_rt/fixunstfdi_test.zig
@@ -7,7 +7,7 @@ fn test__fixunstfdi(a: f128, expected: u64) void {
}
test "fixunstfdi" {
- if (@import("std").Target.current.isWindows()) {
+ if (@import("std").Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
diff --git a/lib/std/special/compiler_rt/fixunstfsi_test.zig b/lib/std/special/compiler_rt/fixunstfsi_test.zig
index af312ddc46..734efff4de 100644
--- a/lib/std/special/compiler_rt/fixunstfsi_test.zig
+++ b/lib/std/special/compiler_rt/fixunstfsi_test.zig
@@ -9,7 +9,7 @@ fn test__fixunstfsi(a: f128, expected: u32) void {
const inf128 = @bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000));
test "fixunstfsi" {
- if (@import("std").Target.current.isWindows()) {
+ if (@import("std").Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
diff --git a/lib/std/special/compiler_rt/fixunstfti_test.zig b/lib/std/special/compiler_rt/fixunstfti_test.zig
index 84dbf991e2..649fcdf1e3 100644
--- a/lib/std/special/compiler_rt/fixunstfti_test.zig
+++ b/lib/std/special/compiler_rt/fixunstfti_test.zig
@@ -9,7 +9,7 @@ fn test__fixunstfti(a: f128, expected: u128) void {
const inf128 = @bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000));
test "fixunstfti" {
- if (@import("std").Target.current.isWindows()) {
+ if (@import("std").Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
diff --git a/lib/std/special/compiler_rt/floattitf_test.zig b/lib/std/special/compiler_rt/floattitf_test.zig
index 0b2b5b958a..4601b90107 100644
--- a/lib/std/special/compiler_rt/floattitf_test.zig
+++ b/lib/std/special/compiler_rt/floattitf_test.zig
@@ -7,7 +7,7 @@ fn test__floattitf(a: i128, expected: f128) void {
}
test "floattitf" {
- if (@import("std").Target.current.isWindows()) {
+ if (@import("std").Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
diff --git a/lib/std/special/compiler_rt/floatuntitf_test.zig b/lib/std/special/compiler_rt/floatuntitf_test.zig
index 8b99bbef5d..34c7407c98 100644
--- a/lib/std/special/compiler_rt/floatuntitf_test.zig
+++ b/lib/std/special/compiler_rt/floatuntitf_test.zig
@@ -7,7 +7,7 @@ fn test__floatuntitf(a: u128, expected: f128) void {
}
test "floatuntitf" {
- if (@import("std").Target.current.isWindows()) {
+ if (@import("std").Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
diff --git a/lib/std/special/compiler_rt/mulXf3_test.zig b/lib/std/special/compiler_rt/mulXf3_test.zig
index 00db984a89..45baa62a17 100644
--- a/lib/std/special/compiler_rt/mulXf3_test.zig
+++ b/lib/std/special/compiler_rt/mulXf3_test.zig
@@ -44,7 +44,7 @@ fn makeNaN128(rand: u64) f128 {
return float_result;
}
test "multf3" {
- if (@import("std").Target.current.isWindows()) {
+ if (@import("std").Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
diff --git a/lib/std/special/compiler_rt/truncXfYf2_test.zig b/lib/std/special/compiler_rt/truncXfYf2_test.zig
index f14dbe6b43..bd05c8652c 100644
--- a/lib/std/special/compiler_rt/truncXfYf2_test.zig
+++ b/lib/std/special/compiler_rt/truncXfYf2_test.zig
@@ -151,7 +151,7 @@ fn test__trunctfsf2(a: f128, expected: u32) void {
}
test "trunctfsf2" {
- if (@import("std").Target.current.isWindows()) {
+ if (@import("std").Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
@@ -190,7 +190,7 @@ fn test__trunctfdf2(a: f128, expected: u64) void {
}
test "trunctfdf2" {
- if (@import("std").Target.current.isWindows()) {
+ if (@import("std").Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
diff --git a/lib/std/target.zig b/lib/std/target.zig
index c9f8a247fe..9007771c1a 100644
--- a/lib/std/target.zig
+++ b/lib/std/target.zig
@@ -53,6 +53,13 @@ pub const Target = struct {
emscripten,
uefi,
other,
+
+ pub fn isDarwin(tag: Tag) bool {
+ return switch (tag) {
+ .ios, .macosx, .watchos, .tvos => true,
+ else => false,
+ };
+ }
};
/// Based on NTDDI version constants from
@@ -921,7 +928,7 @@ pub const Target = struct {
}
/// Returned slice must be freed by the caller.
- pub fn vcpkgTriplet(allocator: *mem.Allocator, target: Target, linkage: std.build.VcpkgLinkage) ![]const u8 {
+ pub fn vcpkgTriplet(target: Target, allocator: *mem.Allocator, linkage: std.build.VcpkgLinkage) ![]const u8 {
const arch = switch (target.cpu.arch) {
.i386 => "x86",
.x86_64 => "x64",
@@ -960,14 +967,6 @@ pub const Target = struct {
return self.zigTriple(allocator);
}
- pub fn zigTripleNoSubArch(self: Target, allocator: *mem.Allocator) ![]u8 {
- return std.fmt.allocPrint(allocator, "{}-{}-{}", .{
- @tagName(self.cpu.arch),
- @tagName(self.os.tag),
- @tagName(self.abi),
- });
- }
-
pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
return std.fmt.allocPrint(allocator, "{}-{}-{}", .{
@tagName(self.cpu.arch),
@@ -1111,11 +1110,11 @@ pub const Target = struct {
}
pub fn exeFileExt(self: Target) []const u8 {
- if (self.isWindows()) {
+ if (self.os.tag == .windows) {
return ".exe";
- } else if (self.isUefi()) {
+ } else if (self.os.tag == .uefi) {
return ".efi";
- } else if (self.isWasm()) {
+ } else if (self.cpu.arch.isWasm()) {
return ".wasm";
} else {
return "";
@@ -1123,7 +1122,7 @@ pub const Target = struct {
}
pub fn staticLibSuffix(self: Target) []const u8 {
- if (self.isWasm()) {
+ if (self.cpu.arch.isWasm()) {
return ".wasm";
}
switch (self.abi) {
@@ -1143,7 +1142,7 @@ pub const Target = struct {
}
pub fn libPrefix(self: Target) []const u8 {
- if (self.isWasm()) {
+ if (self.cpu.arch.isWasm()) {
return "";
}
switch (self.abi) {
@@ -1153,19 +1152,19 @@ pub const Target = struct {
}
pub fn getObjectFormat(self: Target) ObjectFormat {
- if (self.isWindows() or self.isUefi()) {
+ if (self.os.tag == .windows or self.os.tag == .uefi) {
return .coff;
} else if (self.isDarwin()) {
return .macho;
}
- if (self.isWasm()) {
+ if (self.cpu.arch.isWasm()) {
return .wasm;
}
return .elf;
}
pub fn isMinGW(self: Target) bool {
- return self.isWindows() and self.isGnu();
+ return self.os.tag == .windows and self.isGnu();
}
pub fn isGnu(self: Target) bool {
@@ -1176,27 +1175,6 @@ pub const Target = struct {
return self.abi.isMusl();
}
- pub fn isDarwin(self: Target) bool {
- return switch (self.os.tag) {
- .ios, .macosx, .watchos, .tvos => true,
- else => false,
- };
- }
-
- pub fn isWindows(self: Target) bool {
- return switch (self.os.tag) {
- .windows => true,
- else => false,
- };
- }
-
- pub fn isLinux(self: Target) bool {
- return switch (self.os.tag) {
- .linux => true,
- else => false,
- };
- }
-
pub fn isAndroid(self: Target) bool {
return switch (self.abi) {
.android => true,
@@ -1204,36 +1182,12 @@ pub const Target = struct {
};
}
- pub fn isDragonFlyBSD(self: Target) bool {
- return switch (self.os.tag) {
- .dragonfly => true,
- else => false,
- };
- }
-
- pub fn isUefi(self: Target) bool {
- return switch (self.os.tag) {
- .uefi => true,
- else => false,
- };
- }
-
pub fn isWasm(self: Target) bool {
return self.cpu.arch.isWasm();
}
- pub fn isFreeBSD(self: Target) bool {
- return switch (self.os.tag) {
- .freebsd => true,
- else => false,
- };
- }
-
- pub fn isNetBSD(self: Target) bool {
- return switch (self.os.tag) {
- .netbsd => true,
- else => false,
- };
+ pub fn isDarwin(self: Target) bool {
+ return self.os.tag.isDarwin();
}
pub fn isGnuLibC(self: Target) bool {
@@ -1241,11 +1195,11 @@ pub const Target = struct {
}
pub fn wantSharedLibSymLinks(self: Target) bool {
- return !self.isWindows();
+ return self.os.tag != .windows;
}
pub fn osRequiresLibC(self: Target) bool {
- return self.isDarwin() or self.isFreeBSD() or self.isNetBSD();
+ return self.isDarwin() or self.os.tag == .freebsd or self.os.tag == .netbsd;
}
pub fn getArchPtrBitWidth(self: Target) u32 {
@@ -1309,7 +1263,7 @@ pub const Target = struct {
}
pub fn supportsNewStackCall(self: Target) bool {
- return !self.isWasm();
+ return !self.cpu.arch.isWasm();
}
pub const Executor = union(enum) {
@@ -1321,8 +1275,6 @@ pub const Target = struct {
};
pub fn getExternalExecutor(self: Target) Executor {
- if (@as(@TagType(Target), self) == .Native) return .native;
-
// If the target OS matches the host OS, we can use QEMU to emulate a foreign architecture.
if (self.os.tag == builtin.os.tag) {
return switch (self.cpu.arch) {
@@ -1347,22 +1299,18 @@ pub const Target = struct {
};
}
- if (self.isWindows()) {
- switch (self.getArchPtrBitWidth()) {
+ switch (self.os.tag) {
+ .windows => switch (self.getArchPtrBitWidth()) {
32 => return Executor{ .wine = "wine" },
64 => return Executor{ .wine = "wine64" },
else => return .unavailable,
- }
- }
-
- if (self.os == .wasi) {
- switch (self.getArchPtrBitWidth()) {
+ },
+ .wasi => switch (self.getArchPtrBitWidth()) {
32 => return Executor{ .wasmtime = "wasmtime" },
else => return .unavailable,
- }
+ },
+ else => return .unavailable,
}
-
- return .unavailable;
}
pub const FloatAbi = enum {
@@ -1566,12 +1514,12 @@ test "Target.parse" {
std.testing.expect(target.cpu.arch == .aarch64);
std.testing.expect(target.os.tag == .linux);
- std.testing.expect(target.os.version_range.linux.min.major == 3);
- std.testing.expect(target.os.version_range.linux.min.minor == 10);
- std.testing.expect(target.os.version_range.linux.min.patch == 0);
- std.testing.expect(target.os.version_range.linux.max.major == 4);
- std.testing.expect(target.os.version_range.linux.max.minor == 4);
- std.testing.expect(target.os.version_range.linux.max.patch == 1);
+ 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);
diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig
index d617abb821..41def38126 100644
--- a/src-self-hosted/libc_installation.zig
+++ b/src-self-hosted/libc_installation.zig
@@ -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");
@@ -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();
};
diff --git a/test/assemble_and_link.zig b/test/assemble_and_link.zig
index 8c727e87b5..86209bd034 100644
--- a/test/assemble_and_link.zig
+++ b/test/assemble_and_link.zig
@@ -1,8 +1,8 @@
-const builtin = @import("builtin");
+const std = @import("std");
const tests = @import("tests.zig");
pub fn addCases(cases: *tests.CompareOutputContext) void {
- if (builtin.os == builtin.Os.linux and builtin.arch == builtin.Arch.x86_64) {
+ if (std.Target.current.os.tag == .linux and std.Target.current.cpu.arch == .x86_64) {
cases.addAsm("hello world linux x86_64",
\\.text
\\.globl _start
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 91c17d8807..7c1eb6d409 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -1,5 +1,4 @@
const tests = @import("tests.zig");
-const builtin = @import("builtin");
const Target = @import("std").Target;
pub fn addCases(cases: *tests.CompileErrorContext) void {
@@ -387,10 +386,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
, &[_][]const u8{
"tmp.zig:3:5: error: target arch 'wasm32' does not support calling with a new stack",
});
- tc.target = Target{
+ tc.target = tests.Target{
.Cross = .{
.cpu = Target.Cpu.baseline(.wasm32),
- .os = .wasi,
+ .os = Target.Os.defaultVersionRange(.wasi),
.abi = .none,
},
};
@@ -788,10 +787,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
, &[_][]const u8{
"tmp.zig:2:14: error: could not find 'foo' in the inputs or outputs",
});
- tc.target = Target{
+ tc.target = tests.Target{
.Cross = .{
.cpu = Target.Cpu.baseline(.x86_64),
- .os = .linux,
+ .os = Target.Os.defaultVersionRange(.linux),
.abi = .gnu,
},
};
@@ -1453,7 +1452,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:18: error: invalid operands to binary expression: 'error{A}' and 'error{B}'",
});
- if (builtin.os == builtin.Os.linux) {
+ if (Target.current.os.tag == .linux) {
cases.addTest("implicit dependency on libc",
\\extern "c" fn exit(u8) void;
\\export fn entry() void {
diff --git a/test/src/translate_c.zig b/test/src/translate_c.zig
index 21aa92537c..968f09eeb8 100644
--- a/test/src/translate_c.zig
+++ b/test/src/translate_c.zig
@@ -19,7 +19,7 @@ pub const TranslateCContext = struct {
sources: ArrayList(SourceFile),
expected_lines: ArrayList([]const u8),
allow_warnings: bool,
- target: std.Target = .Native,
+ target: build.Target = .Native,
const SourceFile = struct {
filename: []const u8,
@@ -75,7 +75,7 @@ pub const TranslateCContext = struct {
pub fn addWithTarget(
self: *TranslateCContext,
name: []const u8,
- target: std.Target,
+ target: build.Target,
source: []const u8,
expected_lines: []const []const u8,
) void {
diff --git a/test/stack_traces.zig b/test/stack_traces.zig
index fd4ff69964..ab1156c3cb 100644
--- a/test/stack_traces.zig
+++ b/test/stack_traces.zig
@@ -1,4 +1,3 @@
-const builtin = @import("builtin");
const std = @import("std");
const os = std.os;
const tests = @import("tests.zig");
@@ -43,32 +42,32 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
\\}
;
- switch (builtin.os) {
+ switch (builtin.os.tag) {
.freebsd => {
cases.addCase(
"return",
source_return,
[_][]const u8{
// debug
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\source.zig:4:5: [address] in main (test)
\\ return error.TheSkyIsFalling;
\\ ^
\\
,
// release-safe
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\source.zig:4:5: [address] in std.start.main (test)
\\ return error.TheSkyIsFalling;
\\ ^
\\
,
// release-fast
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
,
// release-small
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
},
);
@@ -77,7 +76,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
source_try_return,
[_][]const u8{
// debug
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\source.zig:4:5: [address] in foo (test)
\\ return error.TheSkyIsFalling;
\\ ^
@@ -87,7 +86,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
\\
,
// release-safe
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\source.zig:4:5: [address] in std.start.main (test)
\\ return error.TheSkyIsFalling;
\\ ^
@@ -97,11 +96,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
\\
,
// release-fast
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
,
// release-small
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
},
);
@@ -110,7 +109,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
source_try_try_return_return,
[_][]const u8{
// debug
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\source.zig:12:5: [address] in make_error (test)
\\ return error.TheSkyIsFalling;
\\ ^
@@ -126,7 +125,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
\\
,
// release-safe
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\source.zig:12:5: [address] in std.start.main (test)
\\ return error.TheSkyIsFalling;
\\ ^
@@ -142,11 +141,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
\\
,
// release-fast
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
,
// release-small
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
},
);
@@ -157,25 +156,25 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
source_return,
[_][]const u8{
// debug
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\source.zig:4:5: [address] in main (test)
\\ return error.TheSkyIsFalling;
\\ ^
\\
,
// release-safe
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\source.zig:4:5: [address] in std.start.posixCallMainAndExit (test)
\\ return error.TheSkyIsFalling;
\\ ^
\\
,
// release-fast
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
,
// release-small
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
},
);
@@ -184,7 +183,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
source_try_return,
[_][]const u8{
// debug
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\source.zig:4:5: [address] in foo (test)
\\ return error.TheSkyIsFalling;
\\ ^
@@ -194,7 +193,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
\\
,
// release-safe
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\source.zig:4:5: [address] in std.start.posixCallMainAndExit (test)
\\ return error.TheSkyIsFalling;
\\ ^
@@ -204,11 +203,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
\\
,
// release-fast
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
,
// release-small
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
},
);
@@ -217,7 +216,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
source_try_try_return_return,
[_][]const u8{
// debug
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\source.zig:12:5: [address] in make_error (test)
\\ return error.TheSkyIsFalling;
\\ ^
@@ -233,7 +232,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
\\
,
// release-safe
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\source.zig:12:5: [address] in std.start.posixCallMainAndExit (test)
\\ return error.TheSkyIsFalling;
\\ ^
@@ -249,11 +248,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
\\
,
// release-fast
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
,
// release-small
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
},
);
@@ -278,11 +277,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
\\
,
// release-fast
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
,
// release-small
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
},
);
@@ -311,11 +310,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
\\
,
// release-fast
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
,
// release-small
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
},
);
@@ -356,11 +355,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
\\
,
// release-fast
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
,
// release-small
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
},
);
@@ -371,7 +370,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
source_return,
[_][]const u8{
// debug
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\source.zig:4:5: [address] in main (test.obj)
\\ return error.TheSkyIsFalling;
\\ ^
@@ -381,11 +380,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
// --disabled-- results in segmenetation fault
"",
// release-fast
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
,
// release-small
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
},
);
@@ -407,11 +406,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
// --disabled-- results in segmenetation fault
"",
// release-fast
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
,
// release-small
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
},
);
@@ -439,11 +438,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
// --disabled-- results in segmenetation fault
"",
// release-fast
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
,
// release-small
- \\error: TheSkyIsFalling
+ \\error: TheSkyIsFalling
\\
},
);
diff --git a/test/stage1/behavior/math.zig b/test/stage1/behavior/math.zig
index 65a7d9e1f1..e657b5472b 100644
--- a/test/stage1/behavior/math.zig
+++ b/test/stage1/behavior/math.zig
@@ -529,7 +529,7 @@ test "comptime_int xor" {
}
test "f128" {
- if (std.Target.current.isWindows()) {
+ if (std.Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
@@ -631,7 +631,7 @@ test "NaN comparison" {
// TODO: https://github.com/ziglang/zig/issues/3338
return error.SkipZigTest;
}
- if (std.Target.current.isWindows()) {
+ if (std.Target.current.os.tag == .windows) {
// TODO https://github.com/ziglang/zig/issues/508
return error.SkipZigTest;
}
@@ -666,14 +666,14 @@ test "128-bit multiplication" {
test "vector comparison" {
const S = struct {
fn doTheTest() void {
- var a: @Vector(6, i32) = [_]i32{1, 3, -1, 5, 7, 9};
- var b: @Vector(6, i32) = [_]i32{-1, 3, 0, 6, 10, -10};
- expect(mem.eql(bool, &@as([6]bool, a < b), &[_]bool{false, false, true, true, true, false}));
- expect(mem.eql(bool, &@as([6]bool, a <= b), &[_]bool{false, true, true, true, true, false}));
- expect(mem.eql(bool, &@as([6]bool, a == b), &[_]bool{false, true, false, false, false, false}));
- expect(mem.eql(bool, &@as([6]bool, a != b), &[_]bool{true, false, true, true, true, true}));
- expect(mem.eql(bool, &@as([6]bool, a > b), &[_]bool{true, false, false, false, false, true}));
- expect(mem.eql(bool, &@as([6]bool, a >= b), &[_]bool{true, true, false, false, false, true}));
+ var a: @Vector(6, i32) = [_]i32{ 1, 3, -1, 5, 7, 9 };
+ var b: @Vector(6, i32) = [_]i32{ -1, 3, 0, 6, 10, -10 };
+ expect(mem.eql(bool, &@as([6]bool, a < b), &[_]bool{ false, false, true, true, true, false }));
+ expect(mem.eql(bool, &@as([6]bool, a <= b), &[_]bool{ false, true, true, true, true, false }));
+ expect(mem.eql(bool, &@as([6]bool, a == b), &[_]bool{ false, true, false, false, false, false }));
+ expect(mem.eql(bool, &@as([6]bool, a != b), &[_]bool{ true, false, true, true, true, true }));
+ expect(mem.eql(bool, &@as([6]bool, a > b), &[_]bool{ true, false, false, false, false, true }));
+ expect(mem.eql(bool, &@as([6]bool, a >= b), &[_]bool{ true, true, false, false, false, true }));
}
};
S.doTheTest();
diff --git a/test/standalone.zig b/test/standalone.zig
index 2c5b9c790e..aec9c82726 100644
--- a/test/standalone.zig
+++ b/test/standalone.zig
@@ -18,10 +18,10 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
cases.addBuildFile("test/standalone/use_alias/build.zig");
cases.addBuildFile("test/standalone/brace_expansion/build.zig");
cases.addBuildFile("test/standalone/empty_env/build.zig");
- if (std.Target.current.getOs() != .wasi) {
+ if (std.Target.current.os.tag != .wasi) {
cases.addBuildFile("test/standalone/load_dynamic_library/build.zig");
}
- if (std.Target.current.getArch() == .x86_64) { // TODO add C ABI support for other architectures
+ if (std.Target.current.cpu.arch == .x86_64) { // TODO add C ABI support for other architectures
cases.addBuildFile("test/stage1/c_abi/build.zig");
}
}
diff --git a/test/tests.zig b/test/tests.zig
index c088aafc5f..78eaf56273 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -1,16 +1,15 @@
const std = @import("std");
+const builtin = std.builtin;
const debug = std.debug;
const warn = debug.warn;
const build = std.build;
pub const Target = build.Target;
-pub const CrossTarget = build.CrossTarget;
const Buffer = std.Buffer;
const io = std.io;
const fs = std.fs;
const mem = std.mem;
const fmt = std.fmt;
const ArrayList = std.ArrayList;
-const builtin = @import("builtin");
const Mode = builtin.Mode;
const LibExeObjStep = build.LibExeObjStep;
@@ -54,18 +53,18 @@ const test_targets = blk: {
TestTarget{
.target = Target{
- .Cross = CrossTarget{
- .cpu = Target.Cpu.baseline(.x86_64),
- .os = Target.Os.defaultVersionRange(.linux),
+ .Cross = .{
+ .cpu = std.Target.Cpu.baseline(.x86_64),
+ .os = std.Target.Os.defaultVersionRange(.linux),
.abi = .none,
},
},
},
TestTarget{
.target = Target{
- .Cross = CrossTarget{
- .cpu = Target.Cpu.baseline(.x86_64),
- .os = Target.Os.defaultVersionRange(.linux),
+ .Cross = .{
+ .cpu = std.Target.Cpu.baseline(.x86_64),
+ .os = std.Target.Os.defaultVersionRange(.linux),
.abi = .gnu,
},
},
@@ -73,9 +72,9 @@ const test_targets = blk: {
},
TestTarget{
.target = Target{
- .Cross = CrossTarget{
- .cpu = Target.Cpu.baseline(.x86_64),
- .os = Target.Os.defaultVersionRange(.linux),
+ .Cross = .{
+ .cpu = std.Target.Cpu.baseline(.x86_64),
+ .os = std.Target.Os.defaultVersionRange(.linux),
.abi = .musl,
},
},
@@ -84,18 +83,18 @@ const test_targets = blk: {
TestTarget{
.target = Target{
- .Cross = CrossTarget{
- .cpu = Target.Cpu.baseline(.i386),
- .os = Target.Os.defaultVersionRange(.linux),
+ .Cross = .{
+ .cpu = std.Target.Cpu.baseline(.i386),
+ .os = std.Target.Os.defaultVersionRange(.linux),
.abi = .none,
},
},
},
TestTarget{
.target = Target{
- .Cross = CrossTarget{
- .cpu = Target.Cpu.baseline(.i386),
- .os = Target.Os.defaultVersionRange(.linux),
+ .Cross = .{
+ .cpu = std.Target.Cpu.baseline(.i386),
+ .os = std.Target.Os.defaultVersionRange(.linux),
.abi = .musl,
},
},
@@ -104,18 +103,18 @@ const test_targets = blk: {
TestTarget{
.target = Target{
- .Cross = CrossTarget{
- .cpu = Target.Cpu.baseline(.aarch64),
- .os = Target.Os.defaultVersionRange(.linux),
+ .Cross = .{
+ .cpu = std.Target.Cpu.baseline(.aarch64),
+ .os = std.Target.Os.defaultVersionRange(.linux),
.abi = .none,
},
},
},
TestTarget{
.target = Target{
- .Cross = CrossTarget{
- .cpu = Target.Cpu.baseline(.aarch64),
- .os = Target.Os.defaultVersionRange(.linux),
+ .Cross = .{
+ .cpu = std.Target.Cpu.baseline(.aarch64),
+ .os = std.Target.Os.defaultVersionRange(.linux),
.abi = .musl,
},
},
@@ -123,9 +122,9 @@ const test_targets = blk: {
},
TestTarget{
.target = Target{
- .Cross = CrossTarget{
- .cpu = Target.Cpu.baseline(.aarch64),
- .os = Target.Os.defaultVersionRange(.linux),
+ .Cross = .{
+ .cpu = std.Target.Cpu.baseline(.aarch64),
+ .os = std.Target.Os.defaultVersionRange(.linux),
.abi = .gnu,
},
},
@@ -133,21 +132,25 @@ const test_targets = blk: {
},
TestTarget{
- .target = Target.parse(.{
- .arch_os_abi = "arm-linux-none",
- .cpu_features = "generic+v8a",
- }) catch unreachable,
+ .target = .{
+ .Cross = std.Target.parse(.{
+ .arch_os_abi = "arm-linux-none",
+ .cpu_features = "generic+v8a",
+ }) catch unreachable,
+ },
},
TestTarget{
- .target = Target.parse(.{
- .arch_os_abi = "arm-linux-musleabihf",
- .cpu_features = "generic+v8a",
- }) catch unreachable,
+ .target = .{
+ .Cross = std.Target.parse(.{
+ .arch_os_abi = "arm-linux-musleabihf",
+ .cpu_features = "generic+v8a",
+ }) catch unreachable,
+ },
.link_libc = true,
},
// TODO https://github.com/ziglang/zig/issues/3287
//TestTarget{
- // .target = Target.parse(.{
+ // .target = std.Target.parse(.{
// .arch_os_abi = "arm-linux-gnueabihf",
// .cpu_features = "generic+v8a",
// }) catch unreachable,
@@ -156,18 +159,18 @@ const test_targets = blk: {
TestTarget{
.target = Target{
- .Cross = CrossTarget{
- .cpu = Target.Cpu.baseline(.mipsel),
- .os = Target.Os.defaultVersionRange(.linux),
+ .Cross = .{
+ .cpu = std.Target.Cpu.baseline(.mipsel),
+ .os = std.Target.Os.defaultVersionRange(.linux),
.abi = .none,
},
},
},
TestTarget{
.target = Target{
- .Cross = CrossTarget{
- .cpu = Target.Cpu.baseline(.mipsel),
- .os = Target.Os.defaultVersionRange(.linux),
+ .Cross = .{
+ .cpu = std.Target.Cpu.baseline(.mipsel),
+ .os = std.Target.Os.defaultVersionRange(.linux),
.abi = .musl,
},
},
@@ -176,9 +179,9 @@ const test_targets = blk: {
TestTarget{
.target = Target{
- .Cross = CrossTarget{
- .cpu = Target.Cpu.baseline(.x86_64),
- .os = Target.Os.defaultVersionRange(.macosx),
+ .Cross = .{
+ .cpu = std.Target.Cpu.baseline(.x86_64),
+ .os = std.Target.Os.defaultVersionRange(.macosx),
.abi = .gnu,
},
},
@@ -188,9 +191,9 @@ const test_targets = blk: {
TestTarget{
.target = Target{
- .Cross = CrossTarget{
- .cpu = Target.Cpu.baseline(.i386),
- .os = Target.Os.defaultVersionRange(.windows),
+ .Cross = .{
+ .cpu = std.Target.Cpu.baseline(.i386),
+ .os = std.Target.Os.defaultVersionRange(.windows),
.abi = .msvc,
},
},
@@ -198,9 +201,9 @@ const test_targets = blk: {
TestTarget{
.target = Target{
- .Cross = CrossTarget{
- .cpu = Target.Cpu.baseline(.x86_64),
- .os = Target.Os.defaultVersionRange(.windows),
+ .Cross = .{
+ .cpu = std.Target.Cpu.baseline(.x86_64),
+ .os = std.Target.Os.defaultVersionRange(.windows),
.abi = .msvc,
},
},
@@ -208,9 +211,9 @@ const test_targets = blk: {
TestTarget{
.target = Target{
- .Cross = CrossTarget{
- .cpu = Target.Cpu.baseline(.i386),
- .os = Target.Os.defaultVersionRange(.windows),
+ .Cross = .{
+ .cpu = std.Target.Cpu.baseline(.i386),
+ .os = std.Target.Os.defaultVersionRange(.windows),
.abi = .gnu,
},
},
@@ -219,9 +222,9 @@ const test_targets = blk: {
TestTarget{
.target = Target{
- .Cross = CrossTarget{
- .cpu = Target.Cpu.baseline(.x86_64),
- .os = Target.Os.defaultVersionRange(.windows),
+ .Cross = .{
+ .cpu = std.Target.Cpu.baseline(.x86_64),
+ .os = std.Target.Os.defaultVersionRange(.windows),
.abi = .gnu,
},
},
@@ -438,7 +441,7 @@ pub fn addPkgTests(
if (skip_libc and test_target.link_libc)
continue;
- if (test_target.link_libc and test_target.target.osRequiresLibC()) {
+ if (test_target.link_libc and test_target.target.getTarget().osRequiresLibC()) {
// This would be a redundant test.
continue;
}
@@ -448,8 +451,8 @@ pub fn addPkgTests(
const ArchTag = @TagType(builtin.Arch);
if (test_target.disable_native and
- test_target.target.getOs() == builtin.os and
- test_target.target.getArch() == builtin.arch)
+ test_target.target.getOs() == std.Target.current.os.tag and
+ test_target.target.getArch() == std.Target.current.cpu.arch)
{
continue;
}
@@ -459,7 +462,7 @@ pub fn addPkgTests(
} else false;
if (!want_this_mode) continue;
- const libc_prefix = if (test_target.target.osRequiresLibC())
+ const libc_prefix = if (test_target.target.getTarget().osRequiresLibC())
""
else if (test_target.link_libc)
"c"
@@ -469,7 +472,7 @@ pub fn addPkgTests(
const triple_prefix = if (test_target.target == .Native)
@as([]const u8, "native")
else
- test_target.target.zigTripleNoSubArch(b.allocator) catch unreachable;
+ test_target.target.zigTriple(b.allocator) catch unreachable;
const these_tests = b.addTest(root_src);
const single_threaded_txt = if (test_target.single_threaded) "single" else "multi";
@@ -660,7 +663,7 @@ pub const StackTracesContext = struct {
const delims = [_][]const u8{ ":", ":", ":", " in " };
var marks = [_]usize{0} ** 4;
// offset search past `[drive]:` on windows
- var pos: usize = if (builtin.os == .windows) 2 else 0;
+ var pos: usize = if (std.Target.current.os.tag == .windows) 2 else 0;
for (delims) |delim, i| {
marks[i] = mem.indexOfPos(u8, line, pos, delim) orelse {
try buf.append(line);
diff --git a/test/translate_c.zig b/test/translate_c.zig
index 701513153c..07364fb032 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -1,6 +1,6 @@
const tests = @import("tests.zig");
-const builtin = @import("builtin");
-const Target = @import("std").Target;
+const std = @import("std");
+const Target = std.Target;
pub fn addCases(cases: *tests.TranslateCContext) void {
cases.add("macro line continuation",
@@ -665,7 +665,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
});
- if (builtin.os != builtin.Os.windows) {
+ if (Target.current.os.tag != .windows) {
// Windows treats this as an enum with type c_int
cases.add("big negative enum init values when C ABI supports long long enums",
\\enum EnumWithInits {
@@ -1064,7 +1064,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
});
- if (builtin.os != builtin.Os.windows) {
+ if (Target.current.os.tag != .windows) {
// sysv_abi not currently supported on windows
cases.add("Macro qualified functions",
\\void __attribute__((sysv_abi)) foo(void);
@@ -1093,10 +1093,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const fn1 = ?fn (u8) callconv(.C) void;
});
- cases.addWithTarget("Calling convention", tests.Target{
+ cases.addWithTarget("Calling convention", .{
.Cross = .{
.cpu = Target.Cpu.baseline(.i386),
- .os = .linux,
+ .os = Target.Os.defaultVersionRange(.linux),
.abi = .none,
},
},
@@ -1113,10 +1113,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub fn foo5(a: [*c]f32) callconv(.Thiscall) void;
});
- cases.addWithTarget("Calling convention", Target.parse(.{
- .arch_os_abi = "arm-linux-none",
- .cpu_features = "generic+v8_5a",
- }) catch unreachable,
+ cases.addWithTarget("Calling convention", .{
+ .Cross = Target.parse(.{
+ .arch_os_abi = "arm-linux-none",
+ .cpu_features = "generic+v8_5a",
+ }) catch unreachable,
+ },
\\void __attribute__((pcs("aapcs"))) foo1(float *a);
\\void __attribute__((pcs("aapcs-vfp"))) foo2(float *a);
, &[_][]const u8{
@@ -1124,10 +1126,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub fn foo2(a: [*c]f32) callconv(.AAPCSVFP) void;
});
- cases.addWithTarget("Calling convention", Target.parse(.{
- .arch_os_abi = "aarch64-linux-none",
- .cpu_features = "generic+v8_5a",
- }) catch unreachable,
+ cases.addWithTarget("Calling convention", .{
+ .Cross = Target.parse(.{
+ .arch_os_abi = "aarch64-linux-none",
+ .cpu_features = "generic+v8_5a",
+ }) catch unreachable,
+ },
\\void __attribute__((aarch64_vector_pcs)) foo1(float *a);
, &[_][]const u8{
\\pub fn foo1(a: [*c]f32) callconv(.Vectorcall) void;
@@ -1596,7 +1600,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
});
- if (builtin.os != .windows) {
+ if (Target.current.os.tag != .windows) {
// When clang uses the -windows-none triple it behaves as MSVC and
// interprets the inner `struct Bar` as an anonymous structure
cases.add("type referenced struct",
From dbe4d72bcfb20fc43713781679a0d23aea0a17d9 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 26 Feb 2020 01:18:23 -0500
Subject: [PATCH 07/62] separate std.Target and std.zig.CrossTarget
Zig now supports a more fine-grained sense of what is native and what is
not. Some examples:
This is now allowed:
-target native
Different OS but native CPU, default Windows C ABI:
-target native-windows
This could be useful for example when running in Wine.
Different CPU but native OS, native C ABI.
-target x86_64-native -mcpu=skylake
Different C ABI but otherwise native target:
-target native-native-musl
-target native-native-gnu
Lots of breaking changes to related std lib APIs.
Calls to getOs() will need to be changed to getOsTag().
Calls to getArch() will need to be changed to getCpuArch().
Usage of Target.Cross and Target.Native need to be updated to use
CrossTarget API.
`std.build.Builder.standardTargetOptions` is changed to accept its
parameters as a struct with default values. It now has the ability to
specify a whitelist of targets allowed, as well as the default target.
Rather than two different ways of collecting the target, it's now always
a string that is validated, and prints helpful diagnostics for invalid
targets. This feature should now be actually useful, and contributions
welcome to further improve the user experience.
`std.build.LibExeObjStep.setTheTarget` is removed.
`std.build.LibExeObjStep.setTarget` is updated to take a CrossTarget
parameter.
`std.build.LibExeObjStep.setTargetGLibC` is removed. glibc versions are
handled in the CrossTarget API and can be specified with the `-target`
triple.
`std.builtin.Version` gains a `format` method.
---
build.zig | 2 +-
doc/docgen.zig | 4 +-
lib/std/build.zig | 298 +++++--------
lib/std/build/translate_c.zig | 14 +-
lib/std/builtin.zig | 23 +
lib/std/target.zig | 695 +++++++++---------------------
lib/std/testing.zig | 10 +-
lib/std/zig.zig | 9 +-
lib/std/zig/cross_target.zig | 766 ++++++++++++++++++++++++++++++++++
src-self-hosted/stage2.zig | 143 ++++---
test/compile_errors.zig | 24 +-
test/src/translate_c.zig | 5 +-
test/tests.zig | 236 +++++------
test/translate_c.zig | 36 +-
14 files changed, 1307 insertions(+), 958 deletions(-)
create mode 100644 lib/std/zig/cross_target.zig
diff --git a/build.zig b/build.zig
index e1ae5cf3cd..32694afb0a 100644
--- a/build.zig
+++ b/build.zig
@@ -298,7 +298,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.
diff --git a/doc/docgen.zig b/doc/docgen.zig
index b429c93e65..9b8aca18d0 100644
--- a/doc/docgen.zig
+++ b/doc/docgen.zig
@@ -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;
diff --git a/lib/std/build.zig b/lib/std/build.zig
index 25f7d536b1..92b06a0261 100644
--- a/lib/std/build.zig
+++ b/lib/std/build.zig
@@ -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,77 @@ 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 = .{},
+ };
+
+ /// 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 Arch, OS, and ABI to build for.",
+ ) orelse return args.default_target;
+
+ // TODO add cpu and features as part of the target triple
+
+ var diags: std.Target.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);
+ },
+ else => |e| return e,
+ };
+
+ 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 +850,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)) {
@@ -978,111 +1032,11 @@ test "builder.findProgram compiles" {
_ = 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`.
-pub const CrossTarget = std.Target;
-
-/// Wraps `std.Target` so that it can be annotated as "the native target" or an explicitly specified target.
-pub const Target = union(enum) {
- Native,
- Cross: std.Target,
-
- pub fn getTarget(self: Target) std.Target {
- return switch (self) {
- .Native => std.Target.current,
- .Cross => |t| t,
- };
- }
-
- pub fn getOs(self: Target) std.Target.Os.Tag {
- return self.getTarget().os.tag;
- }
-
- pub fn getCpu(self: Target) std.Target.Cpu {
- return self.getTarget().cpu;
- }
-
- pub fn getAbi(self: Target) std.Target.Abi {
- return self.getTarget().abi;
- }
-
- pub fn getArch(self: Target) std.Target.Cpu.Arch {
- return self.getCpu().arch;
- }
-
- pub fn isFreeBSD(self: Target) bool {
- return self.getTarget().os.tag == .freebsd;
- }
-
- pub fn isDarwin(self: Target) bool {
- return self.getTarget().os.tag.isDarwin();
- }
-
- pub fn isNetBSD(self: Target) bool {
- return self.getTarget().os.tag == .netbsd;
- }
-
- pub fn isUefi(self: Target) bool {
- return self.getTarget().os.tag == .uefi;
- }
-
- pub fn isDragonFlyBSD(self: Target) bool {
- return self.getTarget().os.tag == .dragonfly;
- }
-
- pub fn isLinux(self: Target) bool {
- return self.getTarget().os.tag == .linux;
- }
-
- pub fn isWindows(self: Target) bool {
- return self.getTarget().os.tag == .windows;
- }
-
- pub fn oFileExt(self: Target) []const u8 {
- return self.getTarget().oFileExt();
- }
-
- pub fn exeFileExt(self: Target) []const u8 {
- return self.getTarget().exeFileExt();
- }
-
- pub fn staticLibSuffix(self: Target) []const u8 {
- return self.getTarget().staticLibSuffix();
- }
-
- pub fn libPrefix(self: Target) []const u8 {
- return self.getTarget().libPrefix();
- }
-
- pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
- return self.getTarget().zigTriple(allocator);
- }
-
- pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
- return self.getTarget().linuxTriple(allocator);
- }
-
- pub fn wantSharedLibSymLinks(self: Target) bool {
- return self.getTarget().wantSharedLibSymLinks();
- }
-
- pub fn vcpkgTriplet(self: Target, allocator: *mem.Allocator, linkage: std.build.VcpkgLinkage) ![]const u8 {
- return self.getTarget().vcpkgTriplet(allocator, linkage);
- }
-
- pub fn getExternalExecutor(self: Target) std.Target.Executor {
- switch (self) {
- .Native => return .native,
- .Cross => |t| return t.getExternalExecutor(),
- }
- }
-
- pub fn isGnuLibC(self: Target) bool {
- return self.getTarget().isGnuLibC();
- }
-};
+/// Deprecated. Use `std.zig.CrossTarget`.
+pub const Target = std.zig.CrossTarget;
pub const Pkg = struct {
name: []const u8,
@@ -1135,7 +1089,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,
@@ -1188,7 +1142,6 @@ pub const LibExeObjStep = struct {
install_step: ?*InstallArtifactStep,
libc_file: ?[]const u8 = null,
- target_glibc: ?Version = null,
valgrind_support: ?bool = null,
@@ -1288,7 +1241,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,
@@ -1379,36 +1331,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);
}
@@ -2002,47 +1929,41 @@ 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 != std.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(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 (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.linker_script) |linker_script| {
@@ -2517,10 +2438,7 @@ const VcpkgRootStatus = enum {
Found,
};
-pub const VcpkgLinkage = enum {
- Static,
- Dynamic,
-};
+pub const VcpkgLinkage = std.builtin.LinkMode;
pub const InstallDir = enum {
Prefix,
diff --git a/lib/std/build/translate_c.zig b/lib/std/build/translate_c.zig
index 90e95be5e1..e9e61b190f 100644
--- a/lib/std/build/translate_c.zig
+++ b/lib/std/build/translate_c.zig
@@ -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: build.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: build.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));
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index 3204ce905e..de37fda903 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -429,6 +429,29 @@ pub const Version = struct {
.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
diff --git a/lib/std/target.zig b/lib/std/target.zig
index 9007771c1a..440f50b811 100644
--- a/lib/std/target.zig
+++ b/lib/std/target.zig
@@ -60,6 +60,16 @@ pub const Target = struct {
else => false,
};
}
+
+ pub fn dynamicLibSuffix(tag: Tag) [:0]const u8 {
+ if (tag.isDarwin()) {
+ return ".dylib";
+ }
+ switch (tag) {
+ .windows => return ".dll",
+ else => return ".so",
+ }
+ }
};
/// Based on NTDDI version constants from
@@ -210,64 +220,31 @@ pub const Target = struct {
}
};
- pub fn parse(text: []const u8) !Os {
- var it = mem.separate(text, ".");
- const os_name = it.next().?;
- const tag = std.meta.stringToEnum(Tag, os_name) orelse return error.UnknownOperatingSystem;
- const version_text = it.rest();
- const S = struct {
- fn parseNone(s: []const u8) !void {
- if (s.len != 0) return error.InvalidOperatingSystemVersion;
- }
- fn parseSemVer(s: []const u8, d_range: Version.Range) !Version.Range {
- if (s.len == 0) return d_range;
- var range_it = mem.separate(s, "...");
-
- const min_text = range_it.next().?;
- const min_ver = Version.parse(min_text) catch |err| switch (err) {
- error.Overflow => return error.InvalidOperatingSystemVersion,
- error.InvalidCharacter => return error.InvalidOperatingSystemVersion,
- error.InvalidVersion => return error.InvalidOperatingSystemVersion,
- };
-
- const max_text = range_it.next() orelse return Version.Range{
- .min = min_ver,
- .max = d_range.max,
- };
- const max_ver = Version.parse(max_text) catch |err| switch (err) {
- error.Overflow => return error.InvalidOperatingSystemVersion,
- error.InvalidCharacter => return error.InvalidOperatingSystemVersion,
- error.InvalidVersion => return error.InvalidOperatingSystemVersion,
- };
-
- return Version.Range{ .min = min_ver, .max = max_ver };
- }
- fn parseWindows(s: []const u8, d_range: WindowsVersion.Range) !WindowsVersion.Range {
- if (s.len == 0) return d_range;
- var range_it = mem.separate(s, "...");
-
- const min_text = range_it.next().?;
- const min_ver = std.meta.stringToEnum(WindowsVersion, min_text) orelse
- return error.InvalidOperatingSystemVersion;
-
- const max_text = range_it.next() orelse return WindowsVersion.Range{
- .min = min_ver,
- .max = d_range.max,
- };
- const max_ver = std.meta.stringToEnum(WindowsVersion, max_text) orelse
- return error.InvalidOperatingSystemVersion;
-
- return WindowsVersion.Range{ .min = min_ver, .max = max_ver };
- }
+ pub fn defaultVersionRange(tag: Tag) Os {
+ return .{
+ .tag = tag,
+ .version_range = VersionRange.default(tag),
};
- const d_range = VersionRange.default(tag);
- switch (tag) {
+ }
+
+ pub fn requiresLibC(os: Os) bool {
+ return switch (os.tag) {
+ .freebsd,
+ .netbsd,
+ .macosx,
+ .ios,
+ .tvos,
+ .watchos,
+ .dragonfly,
+ .openbsd,
+ => true,
+
+ .linux,
+ .windows,
.freestanding,
.ananas,
.cloudabi,
- .dragonfly,
.fuchsia,
- .ios,
.kfreebsd,
.lv2,
.solaris,
@@ -282,8 +259,6 @@ pub const Target = struct {
.amdhsa,
.ps4,
.elfiamcu,
- .tvos,
- .watchos,
.mesa3d,
.contiki,
.amdpal,
@@ -293,41 +268,7 @@ pub const Target = struct {
.emscripten,
.uefi,
.other,
- => return Os{
- .tag = tag,
- .version_range = .{ .none = try S.parseNone(version_text) },
- },
-
- .freebsd,
- .macosx,
- .netbsd,
- .openbsd,
- => return Os{
- .tag = tag,
- .version_range = .{ .semver = try S.parseSemVer(version_text, d_range.semver) },
- },
-
- .linux => return Os{
- .tag = tag,
- .version_range = .{
- .linux = .{
- .range = try S.parseSemVer(version_text, d_range.linux.range),
- .glibc = d_range.linux.glibc,
- },
- },
- },
-
- .windows => return Os{
- .tag = tag,
- .version_range = .{ .windows = try S.parseWindows(version_text, d_range.windows) },
- },
- }
- }
-
- pub fn defaultVersionRange(tag: Tag) Os {
- return .{
- .tag = tag,
- .version_range = VersionRange.default(tag),
+ => false,
};
}
};
@@ -434,6 +375,13 @@ pub const Target = struct {
else => false,
};
}
+
+ pub fn oFileExt(abi: Abi) [:0]const u8 {
+ return switch (abi) {
+ .msvc => ".obj",
+ else => ".o",
+ };
+ }
};
pub const ObjectFormat = enum {
@@ -500,6 +448,12 @@ pub const Target = struct {
return Set{ .ints = [1]usize{0} ** usize_count };
}
+ pub fn isEmpty(set: Set) bool {
+ return for (set.ints) |x| {
+ if (x != 0) break false;
+ } else true;
+ }
+
pub fn isEnabled(set: Set, arch_feature_index: Index) bool {
const usize_index = arch_feature_index / @bitSizeOf(usize);
const bit_index = @intCast(ShiftInt, arch_feature_index % @bitSizeOf(usize));
@@ -526,6 +480,15 @@ pub const Target = struct {
set.ints[usize_index] &= ~(@as(usize, 1) << bit_index);
}
+ /// Removes the specified feature but not its dependents.
+ pub fn removeFeatureSet(set: *Set, other_set: Set) void {
+ // TODO should be able to use binary not on @Vector type.
+ // https://github.com/ziglang/zig/issues/903
+ for (set.ints) |*int, i| {
+ int.* &= ~other_set.ints[i];
+ }
+ }
+
pub fn populateDependencies(set: *Set, all_features_list: []const Cpu.Feature) void {
@setEvalBranchQuota(1000000);
@@ -663,7 +626,7 @@ pub const Target = struct {
return cpu;
}
}
- return error.UnknownCpu;
+ return error.UnknownCpuModel;
}
pub fn toElfMachine(arch: Arch) std.elf.EM {
@@ -779,6 +742,66 @@ pub const Target = struct {
};
}
+ pub fn ptrBitWidth(arch: Arch) u32 {
+ switch (arch) {
+ .avr,
+ .msp430,
+ => return 16,
+
+ .arc,
+ .arm,
+ .armeb,
+ .hexagon,
+ .le32,
+ .mips,
+ .mipsel,
+ .powerpc,
+ .r600,
+ .riscv32,
+ .sparc,
+ .sparcel,
+ .tce,
+ .tcele,
+ .thumb,
+ .thumbeb,
+ .i386,
+ .xcore,
+ .nvptx,
+ .amdil,
+ .hsail,
+ .spir,
+ .kalimba,
+ .shave,
+ .lanai,
+ .wasm32,
+ .renderscript32,
+ .aarch64_32,
+ => return 32,
+
+ .aarch64,
+ .aarch64_be,
+ .mips64,
+ .mips64el,
+ .powerpc64,
+ .powerpc64le,
+ .riscv64,
+ .x86_64,
+ .nvptx64,
+ .le64,
+ .amdil64,
+ .hsail64,
+ .spir64,
+ .wasm64,
+ .renderscript64,
+ .amdgcn,
+ .bpfel,
+ .bpfeb,
+ .sparcv9,
+ .s390x,
+ => return 64,
+ }
+ }
+
/// Returns a name that matches the lib/std/target/* directory name.
pub fn genericName(arch: Arch) []const u8 {
return switch (arch) {
@@ -846,16 +869,6 @@ pub const Target = struct {
else => &[0]*const Model{},
};
}
-
- pub fn parse(text: []const u8) !Arch {
- const info = @typeInfo(Arch);
- inline for (info.Enum.fields) |field| {
- if (mem.eql(u8, text, field.name)) {
- return @as(Arch, @field(Arch, field.name));
- }
- }
- return error.UnknownArchitecture;
- }
};
pub const Model = struct {
@@ -872,41 +885,44 @@ pub const Target = struct {
.features = features,
};
}
+
+ pub fn baseline(arch: Arch) *const Model {
+ const S = struct {
+ const generic_model = Model{
+ .name = "generic",
+ .llvm_name = null,
+ .features = Cpu.Feature.Set.empty,
+ };
+ };
+ return switch (arch) {
+ .arm, .armeb, .thumb, .thumbeb => &arm.cpu.baseline,
+ .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic,
+ .avr => &avr.cpu.avr1,
+ .bpfel, .bpfeb => &bpf.cpu.generic,
+ .hexagon => &hexagon.cpu.generic,
+ .mips, .mipsel => &mips.cpu.mips32,
+ .mips64, .mips64el => &mips.cpu.mips64,
+ .msp430 => &msp430.cpu.generic,
+ .powerpc, .powerpc64, .powerpc64le => &powerpc.cpu.generic,
+ .amdgcn => &amdgpu.cpu.generic,
+ .riscv32 => &riscv.cpu.baseline_rv32,
+ .riscv64 => &riscv.cpu.baseline_rv64,
+ .sparc, .sparcv9, .sparcel => &sparc.cpu.generic,
+ .s390x => &systemz.cpu.generic,
+ .i386 => &x86.cpu.pentium4,
+ .x86_64 => &x86.cpu.x86_64,
+ .nvptx, .nvptx64 => &nvptx.cpu.sm_20,
+ .wasm32, .wasm64 => &wasm.cpu.generic,
+
+ else => &S.generic_model,
+ };
+ }
};
/// The "default" set of CPU features for cross-compiling. A conservative set
/// of features that is expected to be supported on most available hardware.
pub fn baseline(arch: Arch) Cpu {
- const S = struct {
- const generic_model = Model{
- .name = "generic",
- .llvm_name = null,
- .features = Cpu.Feature.Set.empty,
- };
- };
- const model = switch (arch) {
- .arm, .armeb, .thumb, .thumbeb => &arm.cpu.baseline,
- .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic,
- .avr => &avr.cpu.avr1,
- .bpfel, .bpfeb => &bpf.cpu.generic,
- .hexagon => &hexagon.cpu.generic,
- .mips, .mipsel => &mips.cpu.mips32,
- .mips64, .mips64el => &mips.cpu.mips64,
- .msp430 => &msp430.cpu.generic,
- .powerpc, .powerpc64, .powerpc64le => &powerpc.cpu.generic,
- .amdgcn => &amdgpu.cpu.generic,
- .riscv32 => &riscv.cpu.baseline_rv32,
- .riscv64 => &riscv.cpu.baseline_rv64,
- .sparc, .sparcv9, .sparcel => &sparc.cpu.generic,
- .s390x => &systemz.cpu.generic,
- .i386 => &x86.cpu.pentium4,
- .x86_64 => &x86.cpu.x86_64,
- .nvptx, .nvptx64 => &nvptx.cpu.sm_20,
- .wasm32, .wasm64 => &wasm.cpu.generic,
-
- else => &S.generic_model,
- };
- return model.toCpu(arch);
+ return Model.baseline(arch).toCpu(arch);
}
};
@@ -918,239 +934,70 @@ pub const Target = struct {
pub const stack_align = 16;
- /// TODO add OS version ranges and glibc version
- pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
- return std.fmt.allocPrint(allocator, "{}-{}-{}", .{
- @tagName(self.cpu.arch),
- @tagName(self.os.tag),
- @tagName(self.abi),
- });
+ pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![:0]u8 {
+ return std.zig.CrossTarget.fromTarget(self).zigTriple(allocator);
}
- /// Returned slice must be freed by the caller.
- pub fn vcpkgTriplet(target: Target, allocator: *mem.Allocator, linkage: std.build.VcpkgLinkage) ![]const u8 {
- const arch = switch (target.cpu.arch) {
- .i386 => "x86",
- .x86_64 => "x64",
+ pub fn linuxTripleSimple(allocator: *mem.Allocator, cpu_arch: Cpu.Arch, os_tag: Os.Tag, abi: Abi) ![:0]u8 {
+ return std.fmt.allocPrint0(allocator, "{}-{}-{}", .{ @tagName(cpu_arch), @tagName(os_tag), @tagName(abi) });
+ }
- .arm,
- .armeb,
- .thumb,
- .thumbeb,
- .aarch64_32,
- => "arm",
+ pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![:0]u8 {
+ return linuxTripleSimple(allocator, self.cpu.arch, self.os.tag, self.abi);
+ }
- .aarch64,
- .aarch64_be,
- => "arm64",
+ pub fn oFileExt(self: Target) [:0]const u8 {
+ return self.abi.oFileExt();
+ }
- else => return error.VcpkgNoSuchArchitecture,
- };
-
- const os = switch (target.os) {
- .windows => "windows",
- .linux => "linux",
- .macosx => "macos",
- else => return error.VcpkgNoSuchOs,
- };
-
- if (linkage == .Static) {
- return try mem.join(allocator, "-", &[_][]const u8{ arch, os, "static" });
- } else {
- return try mem.join(allocator, "-", &[_][]const u8{ arch, os });
+ pub fn exeFileExtSimple(cpu_arch: Cpu.Arch, os_tag: Os.Tag) [:0]const u8 {
+ switch (os_tag) {
+ .windows => return ".exe",
+ .uefi => return ".efi",
+ else => if (cpu_arch.isWasm()) {
+ return ".wasm";
+ } else {
+ return "";
+ },
}
}
- pub fn allocDescription(self: Target, allocator: *mem.Allocator) ![]u8 {
- // TODO is there anything else worthy of the description that is not
- // already captured in the triple?
- return self.zigTriple(allocator);
+ pub fn exeFileExt(self: Target) [:0]const u8 {
+ return exeFileExtSimple(self.cpu.arch, self.os.tag);
}
- pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
- return std.fmt.allocPrint(allocator, "{}-{}-{}", .{
- @tagName(self.cpu.arch),
- @tagName(self.os.tag),
- @tagName(self.abi),
- });
- }
-
- pub const ParseOptions = struct {
- /// This is sometimes called a "triple". It looks roughly like this:
- /// riscv64-linux-gnu
- /// The fields are, respectively:
- /// * CPU Architecture
- /// * Operating System
- /// * C ABI (optional)
- arch_os_abi: []const u8,
-
- /// 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.
- cpu_features: []const u8 = "baseline",
-
- /// 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: ?Cpu.Arch = null,
-
- /// If the OS was determined, this will be populated.
- os: ?Os = null,
-
- /// If the ABI was determined, this will be populated.
- abi: ?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) !Target {
- var dummy_diags: ParseOptions.Diagnostics = undefined;
- var diags = args.diagnostics orelse &dummy_diags;
-
- var it = mem.separate(args.arch_os_abi, "-");
- const arch_name = it.next() orelse return error.MissingArchitecture;
- const arch = try Cpu.Arch.parse(arch_name);
- diags.arch = arch;
-
- const os_name = it.next() orelse return error.MissingOperatingSystem;
- var os = try Os.parse(os_name);
- diags.os = os;
-
- const opt_abi_text = it.next();
- const abi = if (opt_abi_text) |abi_text| blk: {
- var abi_it = mem.separate(abi_text, ".");
- const abi = std.meta.stringToEnum(Abi, abi_it.next().?) orelse
- return error.UnknownApplicationBinaryInterface;
- const abi_ver_text = abi_it.rest();
- if (abi_ver_text.len != 0) {
- if (os.tag == .linux and abi.isGnu()) {
- os.version_range.linux.glibc = Version.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;
- }
- }
- break :blk abi;
- } else Abi.default(arch, os);
- diags.abi = abi;
-
- if (it.next() != null) return error.UnexpectedExtraField;
-
- const all_features = arch.allFeaturesList();
- var index: usize = 0;
- while (index < args.cpu_features.len and
- args.cpu_features[index] != '+' and
- args.cpu_features[index] != '-')
- {
- index += 1;
- }
- const cpu_name = args.cpu_features[0..index];
- diags.cpu_name = cpu_name;
-
- const cpu: Cpu = if (mem.eql(u8, cpu_name, "baseline")) Cpu.baseline(arch) else blk: {
- const cpu_model = try arch.parseCpuModel(cpu_name);
-
- var set = cpu_model.features;
- while (index < args.cpu_features.len) {
- const op = args.cpu_features[index];
- index += 1;
- const start = index;
- while (index < args.cpu_features.len and
- args.cpu_features[index] != '+' and
- args.cpu_features[index] != '-')
- {
- index += 1;
- }
- const feature_name = args.cpu_features[start..index];
- for (all_features) |feature, feat_index_usize| {
- const feat_index = @intCast(Cpu.Feature.Set.Index, feat_index_usize);
- if (mem.eql(u8, feature_name, feature.name)) {
- switch (op) {
- '+' => set.addFeature(feat_index),
- '-' => set.removeFeature(feat_index),
- else => unreachable,
- }
- break;
- }
- } else {
- diags.unknown_feature_name = feature_name;
- return error.UnknownCpuFeature;
- }
- }
- set.populateDependencies(all_features);
- break :blk .{
- .arch = arch,
- .model = cpu_model,
- .features = set,
- };
- };
- return Target{
- .cpu = cpu,
- .os = os,
- .abi = abi,
- };
- }
-
- pub fn oFileExt(self: Target) []const u8 {
- return switch (self.abi) {
- .msvc => ".obj",
- else => ".o",
- };
- }
-
- pub fn exeFileExt(self: Target) []const u8 {
- if (self.os.tag == .windows) {
- return ".exe";
- } else if (self.os.tag == .uefi) {
- return ".efi";
- } else if (self.cpu.arch.isWasm()) {
- return ".wasm";
- } else {
- return "";
- }
- }
-
- pub fn staticLibSuffix(self: Target) []const u8 {
- if (self.cpu.arch.isWasm()) {
+ pub fn staticLibSuffix_cpu_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) [:0]const u8 {
+ if (cpu_arch.isWasm()) {
return ".wasm";
}
- switch (self.abi) {
+ switch (abi) {
.msvc => return ".lib",
else => return ".a",
}
}
- pub fn dynamicLibSuffix(self: Target) []const u8 {
- if (self.isDarwin()) {
- return ".dylib";
- }
- switch (self.os) {
- .windows => return ".dll",
- else => return ".so",
- }
+ pub fn staticLibSuffix(self: Target) [:0]const u8 {
+ return staticLibSuffix_cpu_arch_abi(self.cpu.arch, self.abi);
}
- pub fn libPrefix(self: Target) []const u8 {
- if (self.cpu.arch.isWasm()) {
+ pub fn dynamicLibSuffix(self: Target) [:0]const u8 {
+ return self.os.tag.dynamicLibSuffix();
+ }
+
+ pub fn libPrefix_cpu_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) [:0]const u8 {
+ if (cpu_arch.isWasm()) {
return "";
}
- switch (self.abi) {
+ switch (abi) {
.msvc => return "",
else => return "lib",
}
}
+ pub fn libPrefix(self: Target) [:0]const u8 {
+ return libPrefix_cpu_arch_abi(self.cpu.arch, self.abi);
+ }
+
pub fn getObjectFormat(self: Target) ObjectFormat {
if (self.os.tag == .windows or self.os.tag == .uefi) {
return .coff;
@@ -1190,129 +1037,18 @@ pub const Target = struct {
return self.os.tag.isDarwin();
}
+ pub fn isGnuLibC_os_tag_abi(os_tag: Os.Tag, abi: Abi) bool {
+ return os_tag == .linux and abi.isGnu();
+ }
+
pub fn isGnuLibC(self: Target) bool {
- return self.os.tag == .linux and self.abi.isGnu();
- }
-
- pub fn wantSharedLibSymLinks(self: Target) bool {
- return self.os.tag != .windows;
- }
-
- pub fn osRequiresLibC(self: Target) bool {
- return self.isDarwin() or self.os.tag == .freebsd or self.os.tag == .netbsd;
- }
-
- pub fn getArchPtrBitWidth(self: Target) u32 {
- switch (self.cpu.arch) {
- .avr,
- .msp430,
- => return 16,
-
- .arc,
- .arm,
- .armeb,
- .hexagon,
- .le32,
- .mips,
- .mipsel,
- .powerpc,
- .r600,
- .riscv32,
- .sparc,
- .sparcel,
- .tce,
- .tcele,
- .thumb,
- .thumbeb,
- .i386,
- .xcore,
- .nvptx,
- .amdil,
- .hsail,
- .spir,
- .kalimba,
- .shave,
- .lanai,
- .wasm32,
- .renderscript32,
- .aarch64_32,
- => return 32,
-
- .aarch64,
- .aarch64_be,
- .mips64,
- .mips64el,
- .powerpc64,
- .powerpc64le,
- .riscv64,
- .x86_64,
- .nvptx64,
- .le64,
- .amdil64,
- .hsail64,
- .spir64,
- .wasm64,
- .renderscript64,
- .amdgcn,
- .bpfel,
- .bpfeb,
- .sparcv9,
- .s390x,
- => return 64,
- }
+ return isGnuLibC_os_tag_abi(self.os.tag, self.abi);
}
pub fn supportsNewStackCall(self: Target) bool {
return !self.cpu.arch.isWasm();
}
- pub const Executor = union(enum) {
- native,
- qemu: []const u8,
- wine: []const u8,
- wasmtime: []const u8,
- unavailable,
- };
-
- pub fn getExternalExecutor(self: Target) Executor {
- // If the target OS matches the host OS, we can use QEMU to emulate a foreign architecture.
- if (self.os.tag == builtin.os.tag) {
- return switch (self.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 (self.os.tag) {
- .windows => switch (self.getArchPtrBitWidth()) {
- 32 => return Executor{ .wine = "wine" },
- 64 => return Executor{ .wine = "wine64" },
- else => return .unavailable,
- },
- .wasi => switch (self.getArchPtrBitWidth()) {
- 32 => return Executor{ .wasmtime = "wasmtime" },
- else => return .unavailable,
- },
- else => return .unavailable,
- }
- }
-
pub const FloatAbi = enum {
hard,
soft,
@@ -1359,7 +1095,7 @@ pub const Target = struct {
}![:0]u8 {
const a = allocator;
if (self.isAndroid()) {
- return mem.dupeZ(a, u8, if (self.getArchPtrBitWidth() == 64)
+ return mem.dupeZ(a, u8, if (self.cpu.arch.ptrBitWidth() == 64)
"/system/bin/linker64"
else
"/system/bin/linker");
@@ -1477,52 +1213,3 @@ pub const Target = struct {
}
}
};
-
-test "Target.parse" {
- {
- const target = try Target.parse(.{
- .arch_os_abi = "x86_64-linux-gnu",
- .cpu_features = "x86_64-sse-sse2-avx-cx8",
- });
-
- 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 target = try Target.parse(.{
- .arch_os_abi = "arm-linux-musleabihf",
- .cpu_features = "generic+v8a",
- });
-
- 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 target = try Target.parse(.{
- .arch_os_abi = "aarch64-linux.3.10...4.4.1-gnu.2.27",
- .cpu_features = "generic+v8a",
- });
-
- 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);
- }
-}
diff --git a/lib/std/testing.zig b/lib/std/testing.zig
index 348f651a88..398a71ff37 100644
--- a/lib/std/testing.zig
+++ b/lib/std/testing.zig
@@ -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,16 @@ 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 });
}
diff --git a/lib/std/zig.zig b/lib/std/zig.zig
index d76ed9dfd2..81f34b09c9 100644
--- a/lib/std/zig.zig
+++ b/lib/std/zig.zig
@@ -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());
}
diff --git a/lib/std/zig/cross_target.zig b/lib/std/zig/cross_target.zig
new file mode 100644
index 0000000000..e785c40073
--- /dev/null
+++ b/lib/std/zig/cross_target.zig
@@ -0,0 +1,766 @@
+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.
+pub const CrossTarget = struct {
+ /// `null` means native.
+ cpu_arch: ?Target.Cpu.Arch = null,
+
+ /// If `cpu_arch` is native, `null` means native. Otherwise it means baseline.
+ /// If this is non-null, `cpu_arch` must be specified.
+ cpu_model: ?*const Target.Cpu.Model = null,
+
+ /// Sparse set of CPU features to add to the set from `cpu_model`.
+ /// If this is non-empty, `cpu_arch` must be specified.
+ 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`.
+ /// If this is non-empty, `cpu_arch` must be specified.
+ 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 the native C ABI, if `os_tag` is native, otherwise it means the default C ABI.
+ abi: ?Target.Abi = 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,
+
+ pub const OsVersion = union(enum) {
+ none: void,
+ semver: SemVer,
+ windows: Target.Os.WindowsVersion,
+ };
+
+ pub const SemVer = std.builtin.Version;
+
+ pub fn fromTarget(target: Target) CrossTarget {
+ var result: CrossTarget = .{
+ .cpu_arch = target.cpu.arch,
+ .cpu_model = 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,
+ .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,
+ => {
+ self.os_version_min = .{ .none = {} };
+ self.os_version_max = .{ .none = {} };
+ },
+
+ .freebsd,
+ .macosx,
+ .netbsd,
+ .openbsd,
+ => {
+ 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 };
+ },
+ }
+ }
+
+ 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,
+
+ /// 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 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;
+
+ // Start with everything initialized to default values.
+ var result: CrossTarget = .{};
+
+ 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;
+ 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 = null;
+ } else if (mem.eql(u8, cpu_name, "baseline")) {
+ result.cpu_model = Target.Cpu.Model.baseline(arch);
+ } else {
+ result.cpu_model = 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;
+ }
+
+ pub fn getCpu(self: CrossTarget) Target.Cpu {
+ if (self.cpu_arch) |arch| {
+ if (self.cpu_model) |model| {
+ var adjusted_model = model.toCpu(arch);
+ self.updateCpuFeatures(&adjusted_model.features);
+ return adjusted_model;
+ } else {
+ var adjusted_baseline = Target.Cpu.baseline(arch);
+ self.updateCpuFeatures(&adjusted_baseline.features);
+ return adjusted_baseline;
+ }
+ } else {
+ assert(self.cpu_model == null);
+ assert(self.cpu_features_sub.isEmpty());
+ assert(self.cpu_features_add.isEmpty());
+ // 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;
+ }
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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.?;
+ }
+
+ 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.?;
+ }
+
+ pub fn getAbi(self: CrossTarget) Target.Abi {
+ if (self.abi) |abi| return abi;
+
+ if (self.isNativeOs()) {
+ // 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 isNativeCpu(self: CrossTarget) bool {
+ return self.cpu_arch == null and self.cpu_model == null and
+ self.cpu_features_sub.isEmpty() and self.cpu_features_add.isEmpty();
+ }
+
+ pub fn isNativeOs(self: CrossTarget) bool {
+ return self.os_tag == null and self.os_version_min == null and self.os_version_max == null;
+ }
+
+ pub fn isNativeAbi(self: CrossTarget) bool {
+ return self.abi == null and self.glibc_version == null;
+ }
+
+ pub fn isNative(self: CrossTarget) bool {
+ return self.isNativeCpu() and self.isNativeOs() and self.isNativeAbi();
+ }
+
+ 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.isNativeCpu()) "native" else @tagName(self.getCpuArch());
+ 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.abi) |abi| {
+ try result.print("-{}", .{@tagName(abi)});
+ if (self.glibc_version) |v| {
+ try result.print(".{}", .{v});
+ }
+ } else {
+ assert(self.glibc_version == null);
+ }
+
+ 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,
+ };
+
+ pub fn getExternalExecutor(self: CrossTarget) Executor {
+ const os_tag = self.getOsTag();
+ const cpu_arch = self.getCpuArch();
+
+ // If the target OS matches the host OS, we can use QEMU to emulate a foreign architecture.
+ if (os_tag == Target.current.os.tag) {
+ 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 };
+ }
+
+ 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().?;
+ 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" {
+ {
+ 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);
+ }
+}
diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig
index 7f0f35abe0..ecaad0daf2 100644
--- a/src-self-hosted/stage2.zig
+++ b/src-self-hosted/stage2.zig
@@ -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,
@@ -634,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.cpu = blk: {
- const llvm = @import("llvm.zig");
- const llvm_cpu_name = llvm.GetHostCPUName();
- const llvm_cpu_features = llvm.GetNativeFeatures();
- break :blk try detectNativeCpuWithLLVM(target.cpu.arch, 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{},
@@ -661,7 +658,6 @@ export fn stage2_target_parse(
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,
@@ -681,44 +677,42 @@ fn stage2TargetParse(
zig_triple_oz: ?[*:0]const u8,
mcpu_oz: ?[*:0]const u8,
) !void {
- const target: std.build.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 std.build.Target{
- .Cross = Target.parse(.{
- .arch_os_abi = zig_triple,
- .cpu_features = mcpu,
- .diagnostics = &diags,
- }) catch |err| switch (err) {
- error.UnknownCpu => {
- 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);
- },
- else => |e| return e,
+ var diags: CrossTarget.ParseOptions.Diagnostics = .{};
+ break :blk CrossTarget.parse(.{
+ .arch_os_abi = zig_triple,
+ .cpu_features = mcpu,
+ .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);
+ },
+ else => |e| return e,
};
- } else std.build.Target.Native;
+ } else .{};
try stage1_target.fromTarget(target);
}
@@ -908,8 +902,8 @@ const Stage2Target = extern struct {
dynamic_linker: ?[*:0]const u8,
- fn toTarget(in_target: Stage2Target) std.build.Target {
- if (in_target.is_native) return .Native;
+ 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;
@@ -924,28 +918,11 @@ const Stage2Target = extern struct {
};
}
- fn fromTarget(self: *Stage2Target, build_target: std.build.Target) !void {
+ fn fromTarget(self: *Stage2Target, cross_target: CrossTarget) !void {
const allocator = std.heap.c_allocator;
- var dynamic_linker: ?[*:0]u8 = null;
- const target = switch (build_target) {
- .Native => blk: {
- const info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator);
- if (info.dynamic_linker) |dl| {
- dynamic_linker = dl.ptr;
- }
- // TODO we want to just use 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;
- var t = info.target;
- t.cpu = try detectNativeCpuWithLLVM(arch, llvm_cpu_name, llvm_cpu_features);
- break :blk t;
- },
- .Cross => |t| t,
- };
+ 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,
@@ -1145,7 +1122,7 @@ const Stage2Target = extern struct {
.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 = build_target == .Native,
+ .is_native = cross_target.isNative(),
.glibc_version = glibc_version,
.dynamic_linker = dynamic_linker,
};
@@ -1156,6 +1133,40 @@ fn enumInt(comptime Enum: type, int: c_int) Enum {
return @intToEnum(Enum, @intCast(@TagType(Enum), int));
}
+/// TODO move dynamic linker to be part of the target
+/// TODO self-host this function
+fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8) !Target {
+ var adjusted_target = cross_target.toTarget();
+ if (cross_target.isNativeCpu() or cross_target.isNativeOs()) {
+ const detected_info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator);
+ if (cross_target.isNativeCpu()) {
+ adjusted_target.cpu = detected_info.target.cpu;
+
+ // TODO We want to just use detected_info.target but implementing
+ // CPU model & feature detection is todo so here we rely on LLVM.
+ // There is another occurrence of this; search for detectNativeCpuWithLLVM.
+ const llvm = @import("llvm.zig");
+ const llvm_cpu_name = llvm.GetHostCPUName();
+ const llvm_cpu_features = llvm.GetNativeFeatures();
+ const arch = std.Target.current.cpu.arch;
+ adjusted_target.cpu = try detectNativeCpuWithLLVM(arch, llvm_cpu_name, llvm_cpu_features);
+ }
+ if (cross_target.isNativeOs()) {
+ adjusted_target.os = detected_info.target.os;
+
+ if (detected_info.dynamic_linker) |dl| {
+ dynamic_linker_ptr.* = dl.ptr;
+ }
+ if (cross_target.abi == null) {
+ adjusted_target.abi = detected_info.target.abi;
+ }
+ } else if (cross_target.abi == null) {
+ adjusted_target.abi = Target.Abi.default(adjusted_target.cpu.arch, adjusted_target.os);
+ }
+ }
+ return adjusted_target;
+}
+
// ABI warning
const Stage2GLibCVersion = extern struct {
major: u32,
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 7c1eb6d409..979bf45bbe 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -1,5 +1,5 @@
const tests = @import("tests.zig");
-const Target = @import("std").Target;
+const std = @import("std");
pub fn addCases(cases: *tests.CompileErrorContext) void {
cases.addTest("type mismatch with tuple concatenation",
@@ -386,12 +386,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
, &[_][]const u8{
"tmp.zig:3:5: error: target arch 'wasm32' does not support calling with a new stack",
});
- tc.target = tests.Target{
- .Cross = .{
- .cpu = Target.Cpu.baseline(.wasm32),
- .os = Target.Os.defaultVersionRange(.wasi),
- .abi = .none,
- },
+ tc.target = std.zig.CrossTarget{
+ .cpu_arch = .wasm32,
+ .os_tag = .wasi,
+ .abi = .none,
};
break :x tc;
});
@@ -787,12 +785,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
, &[_][]const u8{
"tmp.zig:2:14: error: could not find 'foo' in the inputs or outputs",
});
- tc.target = tests.Target{
- .Cross = .{
- .cpu = Target.Cpu.baseline(.x86_64),
- .os = Target.Os.defaultVersionRange(.linux),
- .abi = .gnu,
- },
+ tc.target = std.zig.CrossTarget{
+ .cpu_arch = .x86_64,
+ .os_tag = .linux,
+ .abi = .gnu,
};
break :x tc;
});
@@ -1452,7 +1448,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:18: error: invalid operands to binary expression: 'error{A}' and 'error{B}'",
});
- if (Target.current.os.tag == .linux) {
+ if (std.Target.current.os.tag == .linux) {
cases.addTest("implicit dependency on libc",
\\extern "c" fn exit(u8) void;
\\export fn entry() void {
diff --git a/test/src/translate_c.zig b/test/src/translate_c.zig
index 968f09eeb8..9a6bd0d323 100644
--- a/test/src/translate_c.zig
+++ b/test/src/translate_c.zig
@@ -7,6 +7,7 @@ const fmt = std.fmt;
const mem = std.mem;
const fs = std.fs;
const warn = std.debug.warn;
+const CrossTarget = std.zig.CrossTarget;
pub const TranslateCContext = struct {
b: *build.Builder,
@@ -19,7 +20,7 @@ pub const TranslateCContext = struct {
sources: ArrayList(SourceFile),
expected_lines: ArrayList([]const u8),
allow_warnings: bool,
- target: build.Target = .Native,
+ target: CrossTarget = CrossTarget{},
const SourceFile = struct {
filename: []const u8,
@@ -75,7 +76,7 @@ pub const TranslateCContext = struct {
pub fn addWithTarget(
self: *TranslateCContext,
name: []const u8,
- target: build.Target,
+ target: CrossTarget,
source: []const u8,
expected_lines: []const []const u8,
) void {
diff --git a/test/tests.zig b/test/tests.zig
index 78eaf56273..9cf4e7bd98 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -3,7 +3,7 @@ const builtin = std.builtin;
const debug = std.debug;
const warn = debug.warn;
const build = std.build;
-pub const Target = build.Target;
+const CrossTarget = std.zig.CrossTarget;
const Buffer = std.Buffer;
const io = std.io;
const fs = std.fs;
@@ -30,7 +30,7 @@ pub const RunTranslatedCContext = @import("src/run_translated_c.zig").RunTransla
pub const CompareOutputContext = @import("src/compare_output.zig").CompareOutputContext;
const TestTarget = struct {
- target: build.Target = .Native,
+ target: CrossTarget = @as(CrossTarget, .{}),
mode: builtin.Mode = .Debug,
link_libc: bool = false,
single_threaded: bool = false,
@@ -52,105 +52,85 @@ const test_targets = blk: {
},
TestTarget{
- .target = Target{
- .Cross = .{
- .cpu = std.Target.Cpu.baseline(.x86_64),
- .os = std.Target.Os.defaultVersionRange(.linux),
- .abi = .none,
- },
+ .target = .{
+ .cpu_arch = .x86_64,
+ .os_tag = .linux,
+ .abi = .none,
},
},
TestTarget{
- .target = Target{
- .Cross = .{
- .cpu = std.Target.Cpu.baseline(.x86_64),
- .os = std.Target.Os.defaultVersionRange(.linux),
- .abi = .gnu,
- },
+ .target = .{
+ .cpu_arch = .x86_64,
+ .os_tag = .linux,
+ .abi = .gnu,
},
.link_libc = true,
},
TestTarget{
- .target = Target{
- .Cross = .{
- .cpu = std.Target.Cpu.baseline(.x86_64),
- .os = std.Target.Os.defaultVersionRange(.linux),
- .abi = .musl,
- },
- },
- .link_libc = true,
- },
-
- TestTarget{
- .target = Target{
- .Cross = .{
- .cpu = std.Target.Cpu.baseline(.i386),
- .os = std.Target.Os.defaultVersionRange(.linux),
- .abi = .none,
- },
- },
- },
- TestTarget{
- .target = Target{
- .Cross = .{
- .cpu = std.Target.Cpu.baseline(.i386),
- .os = std.Target.Os.defaultVersionRange(.linux),
- .abi = .musl,
- },
- },
- .link_libc = true,
- },
-
- TestTarget{
- .target = Target{
- .Cross = .{
- .cpu = std.Target.Cpu.baseline(.aarch64),
- .os = std.Target.Os.defaultVersionRange(.linux),
- .abi = .none,
- },
- },
- },
- TestTarget{
- .target = Target{
- .Cross = .{
- .cpu = std.Target.Cpu.baseline(.aarch64),
- .os = std.Target.Os.defaultVersionRange(.linux),
- .abi = .musl,
- },
- },
- .link_libc = true,
- },
- TestTarget{
- .target = Target{
- .Cross = .{
- .cpu = std.Target.Cpu.baseline(.aarch64),
- .os = std.Target.Os.defaultVersionRange(.linux),
- .abi = .gnu,
- },
+ .target = .{
+ .cpu_arch = .x86_64,
+ .os_tag = .linux,
+ .abi = .musl,
},
.link_libc = true,
},
TestTarget{
.target = .{
- .Cross = std.Target.parse(.{
- .arch_os_abi = "arm-linux-none",
- .cpu_features = "generic+v8a",
- }) catch unreachable,
+ .cpu_arch = .i386,
+ .os_tag = .linux,
+ .abi = .none,
},
},
TestTarget{
.target = .{
- .Cross = std.Target.parse(.{
- .arch_os_abi = "arm-linux-musleabihf",
- .cpu_features = "generic+v8a",
- }) catch unreachable,
+ .cpu_arch = .i386,
+ .os_tag = .linux,
+ .abi = .musl,
},
.link_libc = true,
},
+
+ TestTarget{
+ .target = .{
+ .cpu_arch = .aarch64,
+ .os_tag = .linux,
+ .abi = .none,
+ },
+ },
+ TestTarget{
+ .target = .{
+ .cpu_arch = .aarch64,
+ .os_tag = .linux,
+ .abi = .musl,
+ },
+ .link_libc = true,
+ },
+ TestTarget{
+ .target = .{
+ .cpu_arch = .aarch64,
+ .os_tag = .linux,
+ .abi = .gnu,
+ },
+ .link_libc = true,
+ },
+
+ TestTarget{
+ .target = CrossTarget.parse(.{
+ .arch_os_abi = "arm-linux-none",
+ .cpu_features = "generic+v8a",
+ }) catch unreachable,
+ },
+ TestTarget{
+ .target = CrossTarget.parse(.{
+ .arch_os_abi = "arm-linux-musleabihf",
+ .cpu_features = "generic+v8a",
+ }) catch unreachable,
+ .link_libc = true,
+ },
// TODO https://github.com/ziglang/zig/issues/3287
//TestTarget{
- // .target = std.Target.parse(.{
+ // .target = CrossTarget.parse(.{
// .arch_os_abi = "arm-linux-gnueabihf",
// .cpu_features = "generic+v8a",
// }) catch unreachable,
@@ -158,75 +138,61 @@ const test_targets = blk: {
//},
TestTarget{
- .target = Target{
- .Cross = .{
- .cpu = std.Target.Cpu.baseline(.mipsel),
- .os = std.Target.Os.defaultVersionRange(.linux),
- .abi = .none,
- },
+ .target = .{
+ .cpu_arch = .mipsel,
+ .os_tag = .linux,
+ .abi = .none,
},
},
TestTarget{
- .target = Target{
- .Cross = .{
- .cpu = std.Target.Cpu.baseline(.mipsel),
- .os = std.Target.Os.defaultVersionRange(.linux),
- .abi = .musl,
- },
+ .target = .{
+ .cpu_arch = .mipsel,
+ .os_tag = .linux,
+ .abi = .musl,
},
.link_libc = true,
},
TestTarget{
- .target = Target{
- .Cross = .{
- .cpu = std.Target.Cpu.baseline(.x86_64),
- .os = std.Target.Os.defaultVersionRange(.macosx),
- .abi = .gnu,
- },
+ .target = .{
+ .cpu_arch = .x86_64,
+ .os_tag = .macosx,
+ .abi = .gnu,
},
// TODO https://github.com/ziglang/zig/issues/3295
.disable_native = true,
},
TestTarget{
- .target = Target{
- .Cross = .{
- .cpu = std.Target.Cpu.baseline(.i386),
- .os = std.Target.Os.defaultVersionRange(.windows),
- .abi = .msvc,
- },
+ .target = .{
+ .cpu_arch = .i386,
+ .os_tag = .windows,
+ .abi = .msvc,
},
},
TestTarget{
- .target = Target{
- .Cross = .{
- .cpu = std.Target.Cpu.baseline(.x86_64),
- .os = std.Target.Os.defaultVersionRange(.windows),
- .abi = .msvc,
- },
+ .target = .{
+ .cpu_arch = .x86_64,
+ .os_tag = .windows,
+ .abi = .msvc,
},
},
TestTarget{
- .target = Target{
- .Cross = .{
- .cpu = std.Target.Cpu.baseline(.i386),
- .os = std.Target.Os.defaultVersionRange(.windows),
- .abi = .gnu,
- },
+ .target = .{
+ .cpu_arch = .i386,
+ .os_tag = .windows,
+ .abi = .gnu,
},
.link_libc = true,
},
TestTarget{
- .target = Target{
- .Cross = .{
- .cpu = std.Target.Cpu.baseline(.x86_64),
- .os = std.Target.Os.defaultVersionRange(.windows),
- .abi = .gnu,
- },
+ .target = .{
+ .cpu_arch = .x86_64,
+ .os_tag = .windows,
+ .abi = .gnu,
},
.link_libc = true,
},
@@ -435,13 +401,13 @@ pub fn addPkgTests(
const step = b.step(b.fmt("test-{}", .{name}), desc);
for (test_targets) |test_target| {
- if (skip_non_native and test_target.target != .Native)
+ if (skip_non_native and !test_target.target.isNative())
continue;
if (skip_libc and test_target.link_libc)
continue;
- if (test_target.link_libc and test_target.target.getTarget().osRequiresLibC()) {
+ if (test_target.link_libc and test_target.target.getOs().requiresLibC()) {
// This would be a redundant test.
continue;
}
@@ -451,8 +417,8 @@ pub fn addPkgTests(
const ArchTag = @TagType(builtin.Arch);
if (test_target.disable_native and
- test_target.target.getOs() == std.Target.current.os.tag and
- test_target.target.getArch() == std.Target.current.cpu.arch)
+ test_target.target.getOsTag() == std.Target.current.os.tag and
+ test_target.target.getCpuArch() == std.Target.current.cpu.arch)
{
continue;
}
@@ -462,17 +428,14 @@ pub fn addPkgTests(
} else false;
if (!want_this_mode) continue;
- const libc_prefix = if (test_target.target.getTarget().osRequiresLibC())
+ const libc_prefix = if (test_target.target.getOs().requiresLibC())
""
else if (test_target.link_libc)
"c"
else
"bare";
- const triple_prefix = if (test_target.target == .Native)
- @as([]const u8, "native")
- else
- test_target.target.zigTriple(b.allocator) catch unreachable;
+ const triple_prefix = test_target.target.zigTriple(b.allocator) catch unreachable;
const these_tests = b.addTest(root_src);
const single_threaded_txt = if (test_target.single_threaded) "single" else "multi";
@@ -486,7 +449,7 @@ pub fn addPkgTests(
these_tests.single_threaded = test_target.single_threaded;
these_tests.setFilter(test_filter);
these_tests.setBuildMode(test_target.mode);
- these_tests.setTheTarget(test_target.target);
+ these_tests.setTarget(test_target.target);
if (test_target.link_libc) {
these_tests.linkSystemLibrary("c");
}
@@ -716,7 +679,7 @@ pub const CompileErrorContext = struct {
link_libc: bool,
is_exe: bool,
is_test: bool,
- target: Target = .Native,
+ target: CrossTarget = CrossTarget{},
const SourceFile = struct {
filename: []const u8,
@@ -808,12 +771,9 @@ pub const CompileErrorContext = struct {
zig_args.append("--output-dir") catch unreachable;
zig_args.append(b.pathFromRoot(b.cache_root)) catch unreachable;
- switch (self.case.target) {
- .Native => {},
- .Cross => {
- try zig_args.append("-target");
- try zig_args.append(try self.case.target.zigTriple(b.allocator));
- },
+ if (!self.case.target.isNative()) {
+ try zig_args.append("-target");
+ try zig_args.append(try self.case.target.zigTriple(b.allocator));
}
switch (self.build_mode) {
diff --git a/test/translate_c.zig b/test/translate_c.zig
index 07364fb032..1d6c2a60ae 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -1,6 +1,6 @@
const tests = @import("tests.zig");
const std = @import("std");
-const Target = std.Target;
+const CrossTarget = std.zig.CrossTarget;
pub fn addCases(cases: *tests.TranslateCContext) void {
cases.add("macro line continuation",
@@ -665,7 +665,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
});
- if (Target.current.os.tag != .windows) {
+ if (std.Target.current.os.tag != .windows) {
// Windows treats this as an enum with type c_int
cases.add("big negative enum init values when C ABI supports long long enums",
\\enum EnumWithInits {
@@ -1064,7 +1064,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
});
- if (Target.current.os.tag != .windows) {
+ if (std.Target.current.os.tag != .windows) {
// sysv_abi not currently supported on windows
cases.add("Macro qualified functions",
\\void __attribute__((sysv_abi)) foo(void);
@@ -1094,11 +1094,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
});
cases.addWithTarget("Calling convention", .{
- .Cross = .{
- .cpu = Target.Cpu.baseline(.i386),
- .os = Target.Os.defaultVersionRange(.linux),
- .abi = .none,
- },
+ .cpu_arch = .i386,
+ .os_tag = .linux,
+ .abi = .none,
},
\\void __attribute__((fastcall)) foo1(float *a);
\\void __attribute__((stdcall)) foo2(float *a);
@@ -1113,12 +1111,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub fn foo5(a: [*c]f32) callconv(.Thiscall) void;
});
- cases.addWithTarget("Calling convention", .{
- .Cross = Target.parse(.{
- .arch_os_abi = "arm-linux-none",
- .cpu_features = "generic+v8_5a",
- }) catch unreachable,
- },
+ cases.addWithTarget("Calling convention", CrossTarget.parse(.{
+ .arch_os_abi = "arm-linux-none",
+ .cpu_features = "generic+v8_5a",
+ }) catch unreachable,
\\void __attribute__((pcs("aapcs"))) foo1(float *a);
\\void __attribute__((pcs("aapcs-vfp"))) foo2(float *a);
, &[_][]const u8{
@@ -1126,12 +1122,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub fn foo2(a: [*c]f32) callconv(.AAPCSVFP) void;
});
- cases.addWithTarget("Calling convention", .{
- .Cross = Target.parse(.{
- .arch_os_abi = "aarch64-linux-none",
- .cpu_features = "generic+v8_5a",
- }) catch unreachable,
- },
+ cases.addWithTarget("Calling convention", CrossTarget.parse(.{
+ .arch_os_abi = "aarch64-linux-none",
+ .cpu_features = "generic+v8_5a",
+ }) catch unreachable,
\\void __attribute__((aarch64_vector_pcs)) foo1(float *a);
, &[_][]const u8{
\\pub fn foo1(a: [*c]f32) callconv(.Vectorcall) void;
@@ -1600,7 +1594,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
});
- if (Target.current.os.tag != .windows) {
+ if (std.Target.current.os.tag != .windows) {
// When clang uses the -windows-none triple it behaves as MSVC and
// interprets the inner `struct Bar` as an anonymous structure
cases.add("type referenced struct",
From c8669a4cf834a6d1dadd9260e94f1781ceed0ec3 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 26 Feb 2020 14:33:10 -0500
Subject: [PATCH 08/62] improve debug info for optionals
---
src/analyze.cpp | 32 ++++++++++++--------------------
1 file changed, 12 insertions(+), 20 deletions(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index ceb232c79d..2c8244d053 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -8719,7 +8719,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;
@@ -8729,35 +8728,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);
From cf233bad5884b9bd782256eb6808fcc6abda645c Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 26 Feb 2020 14:33:31 -0500
Subject: [PATCH 09/62] fix target parsing
---
lib/std/zig/cross_target.zig | 15 +++++++++++++++
src-self-hosted/stage2.zig | 2 +-
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/lib/std/zig/cross_target.zig b/lib/std/zig/cross_target.zig
index e785c40073..6654635b89 100644
--- a/lib/std/zig/cross_target.zig
+++ b/lib/std/zig/cross_target.zig
@@ -177,6 +177,9 @@ pub const CrossTarget = 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,
@@ -219,6 +222,7 @@ pub const CrossTarget = struct {
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();
@@ -614,6 +618,7 @@ pub const CrossTarget = struct {
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
@@ -702,6 +707,16 @@ pub const CrossTarget = struct {
};
test "CrossTarget.parse" {
+ {
+ 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",
diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig
index ecaad0daf2..b2963c8a71 100644
--- a/src-self-hosted/stage2.zig
+++ b/src-self-hosted/stage2.zig
@@ -679,7 +679,7 @@ fn stage2TargetParse(
) !void {
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";
+ const mcpu = if (mcpu_oz) |mcpu_z| mem.toSliceConst(u8, mcpu_z) else null;
var diags: CrossTarget.ParseOptions.Diagnostics = .{};
break :blk CrossTarget.parse(.{
.arch_os_abi = zig_triple,
From cebcacd872a05d8ee3edaafe3eff5cc6e73657b7 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 26 Feb 2020 14:33:36 -0500
Subject: [PATCH 10/62] fix standardTargetOptions and improve init-exe to use
it
---
lib/std/build.zig | 24 +++++++++++++++++++-----
lib/std/special/init-exe/build.zig | 10 ++++++++++
2 files changed, 29 insertions(+), 5 deletions(-)
diff --git a/lib/std/build.zig b/lib/std/build.zig
index 92b06a0261..792781df85 100644
--- a/lib/std/build.zig
+++ b/lib/std/build.zig
@@ -525,7 +525,7 @@ pub const Builder = struct {
pub const StandardTargetOptionsArgs = struct {
whitelist: ?[]const CrossTarget = null,
- default_target: CrossTarget = .{},
+ default_target: CrossTarget = CrossTarget{},
};
/// Exposes standard `zig build` options for choosing a target.
@@ -533,12 +533,12 @@ pub const Builder = struct {
const triple = self.option(
[]const u8,
"target",
- "The Arch, OS, and ABI to build for.",
+ "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: std.Target.ParseOptions.Diagnostics = .{};
+ var diags: CrossTarget.ParseOptions.Diagnostics = .{};
const selected_target = CrossTarget.parse(.{
.arch_os_abi = triple,
.diagnostics = &diags,
@@ -567,7 +567,21 @@ pub const Builder = struct {
}
process.exit(1);
},
- else => |e| return e,
+ 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;
@@ -585,7 +599,7 @@ pub const Builder = struct {
});
for (list) |t| {
const t_triple = t.zigTriple(self.allocator) catch unreachable;
- std.debug.warn(" {}\n", t_triple);
+ 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
diff --git a/lib/std/special/init-exe/build.zig b/lib/std/special/init-exe/build.zig
index 0b7410f2ad..fd71588c5f 100644
--- a/lib/std/special/init-exe/build.zig
+++ b/lib/std/special/init-exe/build.zig
@@ -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();
From 0912484c4f1a8b278a4f04b3baa76cfa38daef6e Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 26 Feb 2020 15:35:48 -0500
Subject: [PATCH 11/62] improve the "external executor" detection logic
---
lib/std/build.zig | 3 +--
lib/std/zig/cross_target.zig | 36 +++++++++++++++++-------------------
src-self-hosted/stage2.zig | 6 +++---
test/stack_traces.zig | 2 +-
4 files changed, 22 insertions(+), 25 deletions(-)
diff --git a/lib/std/build.zig b/lib/std/build.zig
index 792781df85..23db4c3f8e 100644
--- a/lib/std/build.zig
+++ b/lib/std/build.zig
@@ -1141,7 +1141,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,
@@ -1273,7 +1273,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,
diff --git a/lib/std/zig/cross_target.zig b/lib/std/zig/cross_target.zig
index 6654635b89..1e16072815 100644
--- a/lib/std/zig/cross_target.zig
+++ b/lib/std/zig/cross_target.zig
@@ -383,7 +383,7 @@ pub const CrossTarget = struct {
pub fn getAbi(self: CrossTarget) Target.Abi {
if (self.abi) |abi| return abi;
- if (self.isNativeOs()) {
+ 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`.
@@ -441,21 +441,11 @@ pub const CrossTarget = struct {
return Target.libPrefix_cpu_arch_abi(self.getCpuArch(), self.getAbi());
}
- pub fn isNativeCpu(self: CrossTarget) bool {
- return self.cpu_arch == null and self.cpu_model == null and
- self.cpu_features_sub.isEmpty() and self.cpu_features_add.isEmpty();
- }
-
- pub fn isNativeOs(self: CrossTarget) bool {
- return self.os_tag == null and self.os_version_min == null and self.os_version_max == null;
- }
-
- pub fn isNativeAbi(self: CrossTarget) bool {
- return self.abi == null and self.glibc_version == null;
- }
-
pub fn isNative(self: CrossTarget) bool {
- return self.isNativeCpu() and self.isNativeOs() and self.isNativeAbi();
+ return self.cpu_arch == null and self.cpu_model == null 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;
}
pub fn zigTriple(self: CrossTarget, allocator: *mem.Allocator) error{OutOfMemory}![:0]u8 {
@@ -463,7 +453,7 @@ pub const CrossTarget = struct {
return mem.dupeZ(allocator, u8, "native");
}
- const arch_name = if (self.isNativeCpu()) "native" else @tagName(self.getCpuArch());
+ 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 });
@@ -557,12 +547,20 @@ pub const CrossTarget = struct {
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 os_tag = self.getOsTag();
const cpu_arch = self.getCpuArch();
+ const os_tag = self.getOsTag();
+ const os_match = os_tag == Target.current.os.tag;
- // If the target OS matches the host OS, we can use QEMU to emulate a foreign architecture.
- if (os_tag == Target.current.os.tag) {
+ // If the OS matches, and the CPU arch matches, the binary is considered native.
+ if (self.os_tag == null and cpu_arch == Target.current.cpu.arch) {
+ 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" },
diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig
index b2963c8a71..351c6c5357 100644
--- a/src-self-hosted/stage2.zig
+++ b/src-self-hosted/stage2.zig
@@ -1137,9 +1137,9 @@ fn enumInt(comptime Enum: type, int: c_int) Enum {
/// TODO self-host this function
fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8) !Target {
var adjusted_target = cross_target.toTarget();
- if (cross_target.isNativeCpu() or cross_target.isNativeOs()) {
+ if (cross_target.cpu_arch == null or cross_target.os_tag == null) {
const detected_info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator);
- if (cross_target.isNativeCpu()) {
+ if (cross_target.cpu_arch == null) {
adjusted_target.cpu = detected_info.target.cpu;
// TODO We want to just use detected_info.target but implementing
@@ -1151,7 +1151,7 @@ fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8)
const arch = std.Target.current.cpu.arch;
adjusted_target.cpu = try detectNativeCpuWithLLVM(arch, llvm_cpu_name, llvm_cpu_features);
}
- if (cross_target.isNativeOs()) {
+ if (cross_target.os_tag == null) {
adjusted_target.os = detected_info.target.os;
if (detected_info.dynamic_linker) |dl| {
diff --git a/test/stack_traces.zig b/test/stack_traces.zig
index ab1156c3cb..b16bf485c0 100644
--- a/test/stack_traces.zig
+++ b/test/stack_traces.zig
@@ -42,7 +42,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
\\}
;
- switch (builtin.os.tag) {
+ switch (std.Target.current.os.tag) {
.freebsd => {
cases.addCase(
"return",
From 622b5b62c293b767787786e753cecff40f29d7e7 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 26 Feb 2020 16:32:28 -0500
Subject: [PATCH 12/62] fix not setting the dynamic linker path when cross
compiling
---
src-self-hosted/stage2.zig | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig
index 351c6c5357..61068f1737 100644
--- a/src-self-hosted/stage2.zig
+++ b/src-self-hosted/stage2.zig
@@ -668,6 +668,7 @@ export fn stage2_target_parse(
error.ProcessFdQuotaExceeded => return .ProcessFdQuotaExceeded,
error.SystemFdQuotaExceeded => return .SystemFdQuotaExceeded,
error.DeviceBusy => return .DeviceBusy,
+ error.UnknownDynamicLinkerPath => return .UnknownDynamicLinkerPath,
};
return .None;
}
@@ -1137,6 +1138,7 @@ fn enumInt(comptime Enum: type, int: c_int) Enum {
/// TODO self-host this function
fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8) !Target {
var adjusted_target = cross_target.toTarget();
+ var have_native_dl = false;
if (cross_target.cpu_arch == null or cross_target.os_tag == null) {
const detected_info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator);
if (cross_target.cpu_arch == null) {
@@ -1155,6 +1157,7 @@ fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8)
adjusted_target.os = detected_info.target.os;
if (detected_info.dynamic_linker) |dl| {
+ have_native_dl = true;
dynamic_linker_ptr.* = dl.ptr;
}
if (cross_target.abi == null) {
@@ -1164,6 +1167,14 @@ fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8)
adjusted_target.abi = Target.Abi.default(adjusted_target.cpu.arch, adjusted_target.os);
}
}
+ if (!have_native_dl) {
+ dynamic_linker_ptr.* = adjusted_target.getStandardDynamicLinkerPath(
+ std.heap.c_allocator,
+ ) catch |err| switch (err) {
+ error.TargetHasNoDynamicLinker => null,
+ else => |e| return e,
+ };
+ }
return adjusted_target;
}
From 34d2700af42d8f45caaa168b34c34b33bb14cf8d Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 26 Feb 2020 17:35:43 -0500
Subject: [PATCH 13/62] clean up CrossTarget.getExternalExecutor
---
lib/std/zig/cross_target.zig | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/lib/std/zig/cross_target.zig b/lib/std/zig/cross_target.zig
index 1e16072815..fac90ddba8 100644
--- a/lib/std/zig/cross_target.zig
+++ b/lib/std/zig/cross_target.zig
@@ -5,6 +5,7 @@ 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,
@@ -554,9 +555,13 @@ pub const CrossTarget = struct {
const os_tag = self.getOsTag();
const os_match = os_tag == Target.current.os.tag;
- // If the OS matches, and the CPU arch matches, the binary is considered native.
- if (self.os_tag == null and cpu_arch == Target.current.cpu.arch) {
- return .native;
+ // 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.
From 7927764cc21592e19591095105c397736f060edf Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 26 Feb 2020 18:56:43 -0500
Subject: [PATCH 14/62] mips: implement Target.getStandardDynamicLinkerPath
---
lib/std/target.zig | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/lib/std/target.zig b/lib/std/target.zig
index 440f50b811..110aa2dcff 100644
--- a/lib/std/target.zig
+++ b/lib/std/target.zig
@@ -1151,7 +1151,16 @@ pub const Target = struct {
.mipsel,
.mips64,
.mips64el,
- => return error.UnknownDynamicLinkerPath,
+ => {
+ const lib_suffix = switch (self.abi) {
+ .gnuabin32, .gnux32 => "32",
+ .gnuabi64 => "64",
+ else => "",
+ };
+ const is_nan_2008 = mips.featureSetHas(self.cpu.features, .nan2008);
+ const loader = if (is_nan_2008) "ld-linux-mipsn8.so.1" else "ld.so.1";
+ return std.fmt.allocPrint0(a, "/lib{}/{}", .{ lib_suffix, loader });
+ },
.powerpc => return mem.dupeZ(a, u8, "/lib/ld.so.1"),
.powerpc64, .powerpc64le => return mem.dupeZ(a, u8, "/lib64/ld64.so.2"),
From 2387f48d5c5a5ba1410e29098a0cdbf03c3bd9a9 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 26 Feb 2020 20:16:14 -0500
Subject: [PATCH 15/62] fix incorrect builtin import code for windows
---
src-self-hosted/stage2.zig | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig
index 61068f1737..e7265ef6d3 100644
--- a/src-self-hosted/stage2.zig
+++ b/src-self-hosted/stage2.zig
@@ -1029,7 +1029,7 @@ const Stage2Target = extern struct {
.netbsd,
.openbsd,
=> try os_builtin_str_buffer.print(
- \\.semver = .{{
+ \\ .semver = .{{
\\ .min = .{{
\\ .major = {},
\\ .minor = {},
@@ -1041,6 +1041,7 @@ const Stage2Target = extern struct {
\\ .patch = {},
\\ }},
\\ }}}},
+ \\
, .{
target.os.version_range.semver.min.major,
target.os.version_range.semver.min.minor,
@@ -1052,7 +1053,7 @@ const Stage2Target = extern struct {
}),
.linux => try os_builtin_str_buffer.print(
- \\.linux = .{{
+ \\ .linux = .{{
\\ .range = .{{
\\ .min = .{{
\\ .major = {},
@@ -1087,10 +1088,11 @@ const Stage2Target = extern struct {
}),
.windows => try os_builtin_str_buffer.print(
- \\.semver = .{{
+ \\ .windows = .{{
\\ .min = .{},
\\ .max = .{},
\\ }}}},
+ \\
, .{
@tagName(target.os.version_range.windows.min),
@tagName(target.os.version_range.windows.max),
From 6226726571cf6fd500fbc3735e604c85abae641c Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 26 Feb 2020 21:29:31 -0500
Subject: [PATCH 16/62] fix builder.findProgram test
---
lib/std/build.zig | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/lib/std/build.zig b/lib/std/build.zig
index 23db4c3f8e..7852828f7c 100644
--- a/lib/std/build.zig
+++ b/lib/std/build.zig
@@ -1039,9 +1039,10 @@ pub const Builder = struct {
};
test "builder.findProgram compiles" {
- var buf: [50000]u8 = undefined;
- var fba = std.heap.FixedBufferAllocator.init(&buf);
- const builder = try Builder.create(&fba.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;
}
From 36aa3c8e7ff1c945c9014bcd5431a4eedd217e8c Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 27 Feb 2020 11:52:55 -0500
Subject: [PATCH 17/62] fix __stack_chk_guard emitted even when not linking
libc
---
lib/std/special/compiler_rt.zig | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig
index 3126e81b9d..9ed866f62d 100644
--- a/lib/std/special/compiler_rt.zig
+++ b/lib/std/special/compiler_rt.zig
@@ -2,10 +2,7 @@ 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_gnu = std.Target.current.abi.isGnu();
const is_mingw = builtin.os.tag == .windows and is_gnu;
comptime {
@@ -289,7 +286,7 @@ comptime {
else => {},
}
} else {
- if (std.Target.current.isGnuLibC()) {
+ 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 });
From bafa895561a6603351be8d5c3521c9a447645d08 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 27 Feb 2020 12:19:16 -0500
Subject: [PATCH 18/62] compiler-rt: inline at call site to workaround a bug
The bug is #2154
---
lib/std/special/compiler_rt/truncXfYf2.zig | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/lib/std/special/compiler_rt/truncXfYf2.zig b/lib/std/special/compiler_rt/truncXfYf2.zig
index 7c83c66ec0..cba5b85264 100644
--- a/lib/std/special/compiler_rt/truncXfYf2.zig
+++ b/lib/std/special/compiler_rt/truncXfYf2.zig
@@ -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);
From 2536e4c70c6805b096992d4e54dfd2ab9f7fcae3 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 27 Feb 2020 13:31:59 -0500
Subject: [PATCH 19/62] WASI has no dynamic linker
---
lib/std/target.zig | 28 ++++++++++++++++++++++++++--
1 file changed, 26 insertions(+), 2 deletions(-)
diff --git a/lib/std/target.zig b/lib/std/target.zig
index 110aa2dcff..9cd65e7661 100644
--- a/lib/std/target.zig
+++ b/lib/std/target.zig
@@ -1207,6 +1207,31 @@ pub const Target = struct {
=> return error.UnknownDynamicLinkerPath,
},
+ .ananas,
+ .cloudabi,
+ .fuchsia,
+ .kfreebsd,
+ .lv2,
+ .openbsd,
+ .solaris,
+ .haiku,
+ .minix,
+ .rtems,
+ .nacl,
+ .cnk,
+ .aix,
+ .cuda,
+ .nvcl,
+ .amdhsa,
+ .ps4,
+ .elfiamcu,
+ .mesa3d,
+ .contiki,
+ .amdpal,
+ .hermit,
+ .hurd,
+ => return error.UnknownDynamicLinkerPath,
+
.freestanding,
.ios,
.tvos,
@@ -1216,9 +1241,8 @@ pub const Target = struct {
.windows,
.emscripten,
.other,
+ .wasi,
=> return error.TargetHasNoDynamicLinker,
-
- else => return error.UnknownDynamicLinkerPath,
}
}
};
From 3c3316d4ba3ede6172fc0a92b6c4c9b8e601adde Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 27 Feb 2020 13:32:35 -0500
Subject: [PATCH 20/62] update tests to new Target API
---
test/cli.zig | 3 +--
test/compare_output.zig | 9 ++++-----
2 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/test/cli.zig b/test/cli.zig
index b7d03d9e21..bc5a29be44 100644
--- a/test/cli.zig
+++ b/test/cli.zig
@@ -1,5 +1,4 @@
const std = @import("std");
-const builtin = @import("builtin");
const testing = std.testing;
const process = std.process;
const fs = std.fs;
@@ -97,7 +96,7 @@ fn testZigInitExe(zig_exe: []const u8, dir_path: []const u8) !void {
}
fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void {
- if (builtin.os != .linux or builtin.arch != .x86_64) return;
+ if (std.Target.current.os.tag != .linux or std.Target.current.cpu.arch != .x86_64) return;
const example_zig_path = try fs.path.join(a, &[_][]const u8{ dir_path, "example.zig" });
const example_s_path = try fs.path.join(a, &[_][]const u8{ dir_path, "example.s" });
diff --git a/test/compare_output.zig b/test/compare_output.zig
index 7a41d46f54..ec89af35f8 100644
--- a/test/compare_output.zig
+++ b/test/compare_output.zig
@@ -1,4 +1,3 @@
-const builtin = @import("builtin");
const std = @import("std");
const os = std.os;
const tests = @import("tests.zig");
@@ -131,8 +130,8 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
, "Hello, world!\n 12 12 a\n");
cases.addC("number literals",
- \\const builtin = @import("builtin");
- \\const is_windows = builtin.os == builtin.Os.windows;
+ \\const std = @import("std");
+ \\const is_windows = std.Target.current.os.tag == .windows;
\\const c = @cImport({
\\ if (is_windows) {
\\ // See https://github.com/ziglang/zig/issues/515
@@ -306,8 +305,8 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
, "");
cases.addC("casting between float and integer types",
- \\const builtin = @import("builtin");
- \\const is_windows = builtin.os == builtin.Os.windows;
+ \\const std = @import("std");
+ \\const is_windows = std.Target.current.os.tag == .windows;
\\const c = @cImport({
\\ if (is_windows) {
\\ // See https://github.com/ziglang/zig/issues/515
From 70bf8874d7b358545c3370d5e1ae71dfcdf55b93 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 27 Feb 2020 13:32:49 -0500
Subject: [PATCH 21/62] update docgen to new Target API
---
doc/docgen.zig | 81 +++++++++++++++++++++++++-------------------------
1 file changed, 41 insertions(+), 40 deletions(-)
diff --git a/doc/docgen.zig b/doc/docgen.zig
index 9b8aca18d0..83d1a66179 100644
--- a/doc/docgen.zig
+++ b/doc/docgen.zig
@@ -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;
@@ -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("{}", .{ info.url, info.name });
},
- Node.Nav => {
+ .Nav => {
try out.write(toc.toc);
},
- Node.Builtin => |tok| {
+ .Builtin => |tok| {
try out.write("");
try tokenizeAndPrintRaw(tokenizer, out, tok, builtin_code);
try out.write("");
},
- Node.HeaderOpen => |info| {
+ .HeaderOpen => |info| {
try out.print(
"{} §\n",
.{ info.n, info.url, info.url, info.name, info.url, info.n },
);
},
- Node.SeeAlso => |items| {
+ .SeeAlso => |items| {
try out.write("See also:
\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("
\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("$ 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{}
\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
+ 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("\n", .{});
@@ -1207,16 +1208,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
});
try out.print("$ 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("$ 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("$ 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", .{});
},
From f89a1844bfc97f2023fc9961cdf12900ccb77cf8 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 27 Feb 2020 13:33:01 -0500
Subject: [PATCH 22/62] don't error out for targets with unknown standard
dynamic linker path
---
src-self-hosted/stage2.zig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig
index e7265ef6d3..14673b0e98 100644
--- a/src-self-hosted/stage2.zig
+++ b/src-self-hosted/stage2.zig
@@ -668,7 +668,6 @@ export fn stage2_target_parse(
error.ProcessFdQuotaExceeded => return .ProcessFdQuotaExceeded,
error.SystemFdQuotaExceeded => return .SystemFdQuotaExceeded,
error.DeviceBusy => return .DeviceBusy,
- error.UnknownDynamicLinkerPath => return .UnknownDynamicLinkerPath,
};
return .None;
}
@@ -1174,6 +1173,7 @@ fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8)
std.heap.c_allocator,
) catch |err| switch (err) {
error.TargetHasNoDynamicLinker => null,
+ error.UnknownDynamicLinkerPath => null,
else => |e| return e,
};
}
From 662b5f7c6045ba857d0d9abd72350a82f0b7ddf3 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 27 Feb 2020 14:41:44 -0500
Subject: [PATCH 23/62] update docs to latest Target API
---
doc/docgen.zig | 6 +++---
doc/langref.html.in | 30 +++++++++++++++---------------
2 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/doc/docgen.zig b/doc/docgen.zig
index 83d1a66179..5d7f2b7b38 100644
--- a/doc/docgen.zig
+++ b/doc/docgen.zig
@@ -1146,10 +1146,10 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
return parseError(tokenizer, code.source_token, "example failed to compile", .{});
if (code.target_str) |triple| {
- if ((mem.startsWith(u8, triple, "wasm32") or
+ if (mem.startsWith(u8, triple, "wasm32") or
mem.startsWith(u8, triple, "riscv64-linux") or
- mem.startsWith(u8, triple, "x86_64-linux")) and
- (std.Target.current.os.tag != .linux or std.Target.current.cpu.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("
\n", .{});
diff --git a/doc/langref.html.in b/doc/langref.html.in
index e244d69e25..c10fc3ed30 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -965,7 +965,8 @@ const nan = std.math.nan(f128);
but you can switch to {#syntax#}Optimized{#endsyntax#} mode on a per-block basis:
{#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:
{#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" {
{#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.
@@ -7364,8 +7365,6 @@ test "main" {
the {#syntax#}export{#endsyntax#} keyword used on a function:
{#code_begin|obj#}
-const builtin = @import("builtin");
-
comptime {
@export(internalName, .{ .name = "foo", .linkage = .Strong });
}
@@ -9397,7 +9396,7 @@ const separator = if (builtin.os == builtin.Os.windows) '\\' else '/';
{#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" {
@@ -9715,7 +9714,8 @@ WebAssembly.instantiate(typedArray, {
$ node test.js
The result is 3
{#header_open|WASI#}
- Zig's support for WebAssembly System Interface (WASI) is under active development. Example of using the standard library and reading command line arguments:
+ Zig's support for WebAssembly System Interface (WASI) is under active development.
+ Example of using the standard library and reading command line arguments:
{#code_begin|exe|wasi#}
{#target_wasi#}
const std = @import("std");
From 60f2f3457dd73772e7cd60bf5d90358079361d11 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 27 Feb 2020 16:38:10 -0500
Subject: [PATCH 24/62] getStandardDynamicLinkerPath renamed and no allocator
* `std.Target.getStandardDynamicLinkerPath` =>
`std.Target.standardDynamicLinkerPath`
* it now takes a pointer to fixed size array rather than an allocator
* `std.zig.system.NativeTargetInfo.detect` now supports reading
PT_INTERP from /usr/bin/env
---
lib/std/target.zig | 142 +++++++++++++++++++------------------
lib/std/zig/system.zig | 115 +++++++++++++++++++++---------
src-self-hosted/stage2.zig | 16 ++---
3 files changed, 159 insertions(+), 114 deletions(-)
diff --git a/lib/std/target.zig b/lib/std/target.zig
index 9cd65e7661..33019b6bbe 100644
--- a/lib/std/target.zig
+++ b/lib/std/target.zig
@@ -1084,65 +1084,59 @@ pub const Target = struct {
}
}
- /// Caller owns returned memory.
- pub fn getStandardDynamicLinkerPath(
- self: Target,
- allocator: *mem.Allocator,
- ) error{
- OutOfMemory,
- UnknownDynamicLinkerPath,
- TargetHasNoDynamicLinker,
- }![:0]u8 {
- const a = allocator;
+ /// The result will be a slice of `buffer`, pointing at position 0.
+ /// A return value of `null` means the concept of a dynamic linker is not meaningful for that target.
+ pub fn standardDynamicLinkerPath(self: Target, buffer: *[255]u8) ?[]u8 {
+ const S = struct {
+ fn print(b: *[255]u8, comptime fmt: []const u8, args: var) []u8 {
+ return std.fmt.bufPrint(b, fmt, args) catch unreachable;
+ }
+ fn copy(b: *[255]u8, s: []const u8) []u8 {
+ mem.copy(u8, b, s);
+ return b[0..s.len];
+ }
+ };
+ const print = S.print;
+ const copy = S.copy;
+
if (self.isAndroid()) {
- return mem.dupeZ(a, u8, if (self.cpu.arch.ptrBitWidth() == 64)
- "/system/bin/linker64"
- else
- "/system/bin/linker");
+ const suffix = if (self.cpu.arch.ptrBitWidth() == 64) "64" else "";
+ return print(buffer, "/system/bin/linker{}", .{suffix});
}
if (self.isMusl()) {
- var result = try std.Buffer.init(allocator, "/lib/ld-musl-");
- defer result.deinit();
-
- var is_arm = false;
- switch (self.cpu.arch) {
- .arm, .thumb => {
- try result.append("arm");
- is_arm = true;
- },
- .armeb, .thumbeb => {
- try result.append("armeb");
- is_arm = true;
- },
- else => |arch| try result.append(@tagName(arch)),
- }
- if (is_arm and self.getFloatAbi() == .hard) {
- try result.append("hf");
- }
- try result.append(".so.1");
- return result.toOwnedSlice();
+ const is_arm = switch (self.cpu.arch) {
+ .arm, .armeb, .thumb, .thumbeb => true,
+ else => false,
+ };
+ const arch_part = switch (self.cpu.arch) {
+ .arm, .thumb => "arm",
+ .armeb, .thumbeb => "armeb",
+ else => |arch| @tagName(arch),
+ };
+ const arch_suffix = if (is_arm and self.getFloatAbi() == .hard) "hf" else "";
+ return print(buffer, "/lib/ld-musl-{}{}.so.1", .{ arch_part, arch_suffix });
}
switch (self.os.tag) {
- .freebsd => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.1"),
- .netbsd => return mem.dupeZ(a, u8, "/libexec/ld.elf_so"),
- .dragonfly => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.2"),
+ .freebsd => return copy(buffer, "/libexec/ld-elf.so.1"),
+ .netbsd => return copy(buffer, "/libexec/ld.elf_so"),
+ .dragonfly => return copy(buffer, "/libexec/ld-elf.so.2"),
.linux => switch (self.cpu.arch) {
.i386,
.sparc,
.sparcel,
- => return mem.dupeZ(a, u8, "/lib/ld-linux.so.2"),
+ => return copy(buffer, "/lib/ld-linux.so.2"),
- .aarch64 => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64.so.1"),
- .aarch64_be => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64_be.so.1"),
- .aarch64_32 => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64_32.so.1"),
+ .aarch64 => return copy(buffer, "/lib/ld-linux-aarch64.so.1"),
+ .aarch64_be => return copy(buffer, "/lib/ld-linux-aarch64_be.so.1"),
+ .aarch64_32 => return copy(buffer, "/lib/ld-linux-aarch64_32.so.1"),
.arm,
.armeb,
.thumb,
.thumbeb,
- => return mem.dupeZ(a, u8, switch (self.getFloatAbi()) {
+ => return copy(buffer, switch (self.getFloatAbi()) {
.hard => "/lib/ld-linux-armhf.so.3",
else => "/lib/ld-linux.so.3",
}),
@@ -1159,29 +1153,35 @@ pub const Target = struct {
};
const is_nan_2008 = mips.featureSetHas(self.cpu.features, .nan2008);
const loader = if (is_nan_2008) "ld-linux-mipsn8.so.1" else "ld.so.1";
- return std.fmt.allocPrint0(a, "/lib{}/{}", .{ lib_suffix, loader });
+ return print(buffer, "/lib{}/{}", .{ lib_suffix, loader });
},
- .powerpc => return mem.dupeZ(a, u8, "/lib/ld.so.1"),
- .powerpc64, .powerpc64le => return mem.dupeZ(a, u8, "/lib64/ld64.so.2"),
- .s390x => return mem.dupeZ(a, u8, "/lib64/ld64.so.1"),
- .sparcv9 => return mem.dupeZ(a, u8, "/lib64/ld-linux.so.2"),
- .x86_64 => return mem.dupeZ(a, u8, switch (self.abi) {
+ .powerpc => return copy(buffer, "/lib/ld.so.1"),
+ .powerpc64, .powerpc64le => return copy(buffer, "/lib64/ld64.so.2"),
+ .s390x => return copy(buffer, "/lib64/ld64.so.1"),
+ .sparcv9 => return copy(buffer, "/lib64/ld-linux.so.2"),
+ .x86_64 => return copy(buffer, switch (self.abi) {
.gnux32 => "/libx32/ld-linux-x32.so.2",
else => "/lib64/ld-linux-x86-64.so.2",
}),
- .riscv32 => return mem.dupeZ(a, u8, "/lib/ld-linux-riscv32-ilp32.so.1"),
- .riscv64 => return mem.dupeZ(a, u8, "/lib/ld-linux-riscv64-lp64.so.1"),
+ .riscv32 => return copy(buffer, "/lib/ld-linux-riscv32-ilp32.so.1"),
+ .riscv64 => return copy(buffer, "/lib/ld-linux-riscv64-lp64.so.1"),
+ // Architectures in this list have been verified as not having a standard
+ // dynamic linker path.
.wasm32,
.wasm64,
- => return error.TargetHasNoDynamicLinker,
-
- .arc,
- .avr,
.bpfel,
.bpfeb,
+ .nvptx,
+ .nvptx64,
+ => return null,
+
+ // TODO go over each item in this list and either move it to the above list, or
+ // implement the standard dynamic linker path code for it.
+ .arc,
+ .avr,
.hexagon,
.msp430,
.r600,
@@ -1189,8 +1189,6 @@ pub const Target = struct {
.tce,
.tcele,
.xcore,
- .nvptx,
- .nvptx64,
.le32,
.le64,
.amdil,
@@ -1204,9 +1202,25 @@ pub const Target = struct {
.lanai,
.renderscript32,
.renderscript64,
- => return error.UnknownDynamicLinkerPath,
+ => return null,
},
+ // Operating systems in this list have been verified as not having a standard
+ // dynamic linker path.
+ .freestanding,
+ .ios,
+ .tvos,
+ .watchos,
+ .macosx,
+ .uefi,
+ .windows,
+ .emscripten,
+ .other,
+ .wasi,
+ => return null,
+
+ // TODO go over each item in this list and either move it to the above list, or
+ // implement the standard dynamic linker path code for it.
.ananas,
.cloudabi,
.fuchsia,
@@ -1230,19 +1244,7 @@ pub const Target = struct {
.amdpal,
.hermit,
.hurd,
- => return error.UnknownDynamicLinkerPath,
-
- .freestanding,
- .ios,
- .tvos,
- .watchos,
- .macosx,
- .uefi,
- .windows,
- .emscripten,
- .other,
- .wasi,
- => return error.TargetHasNoDynamicLinker,
+ => return null,
}
}
};
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index 5c9b71001b..d2828a88a1 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -167,7 +167,15 @@ pub const NativePaths = struct {
pub const NativeTargetInfo = struct {
target: Target,
- dynamic_linker: ?[:0]u8,
+
+ /// Contains the memory used to store the dynamic linker path. This field should
+ /// not be used directly. See `dynamicLinker` and `setDynamicLinker`. This field
+ /// exists so that this API requires no allocator.
+ dynamic_linker_buffer: [255]u8 = undefined,
+
+ /// Used to construct the dynamic linker path. This field should not be used
+ /// directly. See `dynamicLinker` and `setDynamicLinker`.
+ dynamic_linker_max: ?u8 = null,
pub const DetectError = error{
OutOfMemory,
@@ -181,6 +189,7 @@ pub const NativeTargetInfo = struct {
/// Detects the native CPU model & features, operating system & version, and C ABI & dynamic linker.
/// On Linux, this is additionally responsible for detecting the native glibc version when applicable.
+ /// TODO Remove the allocator requirement from this.
pub fn detect(allocator: *Allocator) DetectError!NativeTargetInfo {
const arch = Target.current.cpu.arch;
const os_tag = Target.current.os.tag;
@@ -188,8 +197,7 @@ pub const NativeTargetInfo = struct {
// TODO Detect native CPU model & features. Until that is implemented we hard code baseline.
const cpu = Target.Cpu.baseline(arch);
- // TODO Detect native operating system version. Until that is implemented we use the minimum version
- // of the default range.
+ // TODO Detect native operating system version. Until that is implemented we use the default range.
const os = Target.Os.defaultVersionRange(os_tag);
return detectAbiAndDynamicLinker(allocator, cpu, os);
@@ -201,6 +209,21 @@ pub const NativeTargetInfo = struct {
self.* = undefined;
}
+ /// The returned memory has the same lifetime as the `NativeTargetInfo`.
+ pub fn dynamicLinker(self: *const NativeTargetInfo) ?[]const u8 {
+ const m = self.dynamic_linker_max orelse return null;
+ return self.dynamic_linker_buffer[0 .. m + 1];
+ }
+
+ pub fn setDynamicLinker(self: *NativeTargetInfo, dl_or_null: ?[]const u8) void {
+ if (dl_or_null) |dl| {
+ mem.copy(u8, &self.dynamic_linker_buffer, dl);
+ self.dynamic_linker_max = @intCast(u8, dl.len - 1);
+ } else {
+ self.dynamic_linker_max = null;
+ }
+ }
+
/// 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
@@ -245,10 +268,11 @@ pub const NativeTargetInfo = struct {
.os = os,
.abi = abi,
};
- const standard_ld_path = target.getStandardDynamicLinkerPath(allocator) catch |err| switch (err) {
- error.OutOfMemory => return error.OutOfMemory,
- error.UnknownDynamicLinkerPath, error.TargetHasNoDynamicLinker => continue,
- };
+ var buf: [255]u8 = undefined;
+ const standard_ld_path = if (target.standardDynamicLinkerPath(&buf)) |s|
+ try mem.dupe(allocator, u8, s)
+ else
+ continue;
errdefer allocator.free(standard_ld_path);
try ld_info_list.append(.{
.ld_path = standard_ld_path,
@@ -294,28 +318,29 @@ pub const NativeTargetInfo = struct {
}
}
- return NativeTargetInfo{
+ var result: NativeTargetInfo = .{
.target = .{
.cpu = cpu,
.os = os_adjusted,
.abi = found_ld_info.abi,
},
- .dynamic_linker = try mem.dupeZ(allocator, u8, found_ld_path),
};
+ result.setDynamicLinker(found_ld_path);
+ return result;
}
// 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 abiAndDynamicLinkerFromUsrBinEnv(allocator, cpu, os) catch |err| switch (err) {
- error.OutOfMemory => return error.OutOfMemory,
- error.FileSystem => return error.FileSystem,
- error.SystemResources => return error.SystemResources,
- error.SymLinkLoop => return error.SymLinkLoop,
- error.ProcessFdQuotaExceeded => return error.ProcessFdQuotaExceeded,
- error.SystemFdQuotaExceeded => return error.SystemFdQuotaExceeded,
- error.DeviceBusy => return error.DeviceBusy,
+ return abiAndDynamicLinkerFromUsrBinEnv(cpu, os) catch |err| switch (err) {
+ error.FileSystem,
+ error.SystemResources,
+ error.SymLinkLoop,
+ error.ProcessFdQuotaExceeded,
+ error.SystemFdQuotaExceeded,
+ error.DeviceBusy,
+ => |e| return e,
error.UnableToReadElfFile,
error.ElfNotADynamicExecutable,
@@ -327,6 +352,8 @@ pub const NativeTargetInfo = struct {
error.InvalidElfMagic,
error.UsrBinEnvNotAvailable,
error.Unexpected,
+ error.UnexpectedEndOfFile,
+ error.NameTooLong,
// Finally, we fall back on the standard path.
=> defaultAbiAndDynamicLinker(allocator, cpu, os),
};
@@ -362,11 +389,7 @@ pub const NativeTargetInfo = struct {
};
}
- fn abiAndDynamicLinkerFromUsrBinEnv(
- allocator: *Allocator,
- cpu: Target.Cpu,
- os: Target.Os,
- ) !NativeTargetInfo {
+ fn abiAndDynamicLinkerFromUsrBinEnv(cpu: Target.Cpu, os: Target.Os) !NativeTargetInfo {
const env_file = std.fs.openFileAbsoluteC("/usr/bin/env", .{}) catch |err| switch (err) {
error.NoSpaceLeft => unreachable,
error.NameTooLong => unreachable,
@@ -409,6 +432,14 @@ pub const NativeTargetInfo = struct {
const phnum = elfInt(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum);
const shstrndx = elfInt(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx);
+ var result: NativeTargetInfo = .{
+ .target = .{
+ .cpu = cpu,
+ .os = os,
+ .abi = Target.Abi.default(cpu.arch, os),
+ },
+ };
+
const ph_total_size = std.math.mul(u32, phentsize, phnum) catch |err| switch (err) {
error.Overflow => return error.InvalidElfProgramHeaders,
};
@@ -430,7 +461,22 @@ pub const NativeTargetInfo = struct {
const p_type = elfInt(is_64, need_bswap, ph32.p_type, ph64.p_type);
switch (p_type) {
elf.PT_INTERP => {
- std.debug.warn("found PT_INTERP\n", .{});
+ 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);
+ var interp_buf: [255]u8 = undefined;
+ if (p_filesz > interp_buf.len) return error.NameTooLong;
+ var read_offset: usize = 0;
+ while (true) {
+ const len = try wrapRead(env_file.pread(
+ interp_buf[read_offset .. p_filesz - read_offset],
+ p_offset + read_offset,
+ ));
+ if (len == 0) return error.UnexpectedEndOfFile;
+ read_offset += len;
+ if (read_offset == p_filesz) break;
+ }
+ // PT_INTERP includes a null byte in p_filesz.
+ result.setDynamicLinker(interp_buf[0 .. p_filesz - 1]);
},
elf.PT_DYNAMIC => {
std.debug.warn("found PT_DYNAMIC\n", .{});
@@ -440,7 +486,7 @@ pub const NativeTargetInfo = struct {
}
}
- return error.OutOfMemory; // TODO
+ return result;
}
fn wrapRead(res: std.os.ReadError!usize) !usize {
@@ -457,18 +503,17 @@ pub const NativeTargetInfo = struct {
}
fn defaultAbiAndDynamicLinker(allocator: *Allocator, cpu: Target.Cpu, os: Target.Os) !NativeTargetInfo {
- const target: Target = .{
- .cpu = cpu,
- .os = os,
- .abi = Target.Abi.default(cpu.arch, os),
- };
- return @as(NativeTargetInfo, .{
- .target = target,
- .dynamic_linker = target.getStandardDynamicLinkerPath(allocator) catch |err| switch (err) {
- error.OutOfMemory => return error.OutOfMemory,
- error.UnknownDynamicLinkerPath, error.TargetHasNoDynamicLinker => null,
+ var result: NativeTargetInfo = .{
+ .target = .{
+ .cpu = cpu,
+ .os = os,
+ .abi = Target.Abi.default(cpu.arch, os),
},
- });
+ };
+ if (result.target.standardDynamicLinkerPath(&result.dynamic_linker_buffer)) |s| {
+ result.dynamic_linker_max = @intCast(u8, s.len - 1);
+ }
+ return result;
}
};
diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig
index 14673b0e98..5358c4fedc 100644
--- a/src-self-hosted/stage2.zig
+++ b/src-self-hosted/stage2.zig
@@ -1157,9 +1157,9 @@ fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8)
if (cross_target.os_tag == null) {
adjusted_target.os = detected_info.target.os;
- if (detected_info.dynamic_linker) |dl| {
+ if (detected_info.dynamicLinker()) |dl| {
have_native_dl = true;
- dynamic_linker_ptr.* = dl.ptr;
+ dynamic_linker_ptr.* = try mem.dupeZ(std.heap.c_allocator, u8, dl);
}
if (cross_target.abi == null) {
adjusted_target.abi = detected_info.target.abi;
@@ -1169,13 +1169,11 @@ fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8)
}
}
if (!have_native_dl) {
- dynamic_linker_ptr.* = adjusted_target.getStandardDynamicLinkerPath(
- std.heap.c_allocator,
- ) catch |err| switch (err) {
- error.TargetHasNoDynamicLinker => null,
- error.UnknownDynamicLinkerPath => null,
- else => |e| return e,
- };
+ var buf: [255]u8 = undefined;
+ dynamic_linker_ptr.* = if (adjusted_target.standardDynamicLinkerPath(&buf)) |s|
+ try mem.dupeZ(std.heap.c_allocator, u8, s)
+ else
+ null;
}
return adjusted_target;
}
From fd006c1c74a43827a6f1c32e289ba57cafa874be Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 27 Feb 2020 17:20:40 -0500
Subject: [PATCH 25/62] std.zig.system.NativeTargetInfo.detect: almost no
Allocator
---
lib/std/process.zig | 4 +++
lib/std/target.zig | 12 ++++----
lib/std/zig/system.zig | 62 ++++++++++++++++++--------------------
src-self-hosted/stage2.zig | 4 +--
4 files changed, 42 insertions(+), 40 deletions(-)
diff --git a/lib/std/process.zig b/lib/std/process.zig
index 118b5d9ab4..01b9947518 100644
--- a/lib/std/process.zig
+++ b/lib/std/process.zig
@@ -609,6 +609,10 @@ 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{},
diff --git a/lib/std/target.zig b/lib/std/target.zig
index 33019b6bbe..379ae72afe 100644
--- a/lib/std/target.zig
+++ b/lib/std/target.zig
@@ -1084,16 +1084,16 @@ pub const Target = struct {
}
}
- /// The result will be a slice of `buffer`, pointing at position 0.
+ /// The result will be a byte index *pointing at the final byte*. In other words, length minus one.
/// A return value of `null` means the concept of a dynamic linker is not meaningful for that target.
- pub fn standardDynamicLinkerPath(self: Target, buffer: *[255]u8) ?[]u8 {
+ pub fn standardDynamicLinkerPath(self: Target, buffer: *[255]u8) ?u8 {
const S = struct {
- fn print(b: *[255]u8, comptime fmt: []const u8, args: var) []u8 {
- return std.fmt.bufPrint(b, fmt, args) catch unreachable;
+ fn print(b: *[255]u8, comptime fmt: []const u8, args: var) u8 {
+ return @intCast(u8, (std.fmt.bufPrint(b, fmt, args) catch unreachable).len - 1);
}
- fn copy(b: *[255]u8, s: []const u8) []u8 {
+ fn copy(b: *[255]u8, s: []const u8) u8 {
mem.copy(u8, b, s);
- return b[0..s.len];
+ return @intCast(u8, s.len - 1);
}
};
const print = S.print;
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index d2828a88a1..e8c95f5125 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -189,7 +189,9 @@ pub const NativeTargetInfo = struct {
/// Detects the native CPU model & features, operating system & version, and C ABI & dynamic linker.
/// On Linux, this is additionally responsible for detecting the native glibc version when applicable.
- /// TODO Remove the allocator requirement from this.
+ /// 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) DetectError!NativeTargetInfo {
const arch = Target.current.cpu.arch;
const os_tag = Target.current.os.tag;
@@ -203,15 +205,9 @@ pub const NativeTargetInfo = struct {
return detectAbiAndDynamicLinker(allocator, cpu, os);
}
- /// Must be the same `Allocator` passed to `detect`.
- pub fn deinit(self: *NativeTargetInfo, allocator: *Allocator) void {
- if (self.dynamic_linker) |dl| allocator.free(dl);
- self.* = undefined;
- }
-
/// The returned memory has the same lifetime as the `NativeTargetInfo`.
pub fn dynamicLinker(self: *const NativeTargetInfo) ?[]const u8 {
- const m = self.dynamic_linker_max orelse return null;
+ const m: usize = self.dynamic_linker_max orelse return null;
return self.dynamic_linker_buffer[0 .. m + 1];
}
@@ -228,13 +224,14 @@ pub const NativeTargetInfo = struct {
/// 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,
) DetectError!NativeTargetInfo {
if (!comptime Target.current.hasDynamicLinker()) {
- return defaultAbiAndDynamicLinker(allocator, cpu, os);
+ return defaultAbiAndDynamicLinker(cpu, os);
}
// 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.
@@ -242,15 +239,15 @@ pub const NativeTargetInfo = struct {
// and supported by Zig. But that means that we must detect the system ABI here rather than
// relying on `Target.current`.
const LdInfo = struct {
- ld_path: []u8,
+ ld_path_buffer: [255]u8,
+ ld_path_max: 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();
- }
+ pub fn ldPath(self: *const @This()) []const u8 {
+ const m: usize = self.ld_path_max;
+ return self.ld_path_buffer[0 .. m + 1];
+ }
+ };
const all_abis = comptime blk: {
assert(@enumToInt(Target.Abi.none) == 0);
const fields = std.meta.fields(Target.Abi)[1..];
@@ -260,6 +257,9 @@ pub const NativeTargetInfo = struct {
}
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`.
@@ -268,17 +268,17 @@ pub const NativeTargetInfo = struct {
.os = os,
.abi = abi,
};
- var buf: [255]u8 = undefined;
- const standard_ld_path = if (target.standardDynamicLinkerPath(&buf)) |s|
- try mem.dupe(allocator, u8, s)
- else
- continue;
- errdefer allocator.free(standard_ld_path);
- try ld_info_list.append(.{
- .ld_path = standard_ld_path,
+ const ld_info = &ld_info_list_buffer[ld_info_list_len];
+ ld_info_list_len += 1;
+
+ ld_info.* = .{
+ .ld_path_buffer = undefined,
+ .ld_path_max = undefined,
.abi = abi,
- });
+ };
+ ld_info.ld_path_max = target.standardDynamicLinkerPath(&ld_info.ld_path_buffer) orelse continue;
}
+ const ld_info_list = ld_info_list_buffer[0..ld_info_list_len];
// Best case scenario: the executable is dynamically linked, and we can iterate
// over our own shared objects and find a dynamic linker.
@@ -292,8 +292,8 @@ pub const NativeTargetInfo = struct {
// 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.toSlice()) |ld_info| {
- const standard_ld_basename = fs.path.basename(ld_info.ld_path);
+ for (ld_info_list) |ld_info| {
+ const standard_ld_basename = fs.path.basename(ld_info.ldPath());
if (std.mem.endsWith(u8, lib_path, standard_ld_basename)) {
found_ld_info = ld_info;
found_ld_path = lib_path;
@@ -355,7 +355,7 @@ pub const NativeTargetInfo = struct {
error.UnexpectedEndOfFile,
error.NameTooLong,
// Finally, we fall back on the standard path.
- => defaultAbiAndDynamicLinker(allocator, cpu, os),
+ => defaultAbiAndDynamicLinker(cpu, os),
};
}
@@ -502,7 +502,7 @@ pub const NativeTargetInfo = struct {
};
}
- fn defaultAbiAndDynamicLinker(allocator: *Allocator, cpu: Target.Cpu, os: Target.Os) !NativeTargetInfo {
+ fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os) !NativeTargetInfo {
var result: NativeTargetInfo = .{
.target = .{
.cpu = cpu,
@@ -510,9 +510,7 @@ pub const NativeTargetInfo = struct {
.abi = Target.Abi.default(cpu.arch, os),
},
};
- if (result.target.standardDynamicLinkerPath(&result.dynamic_linker_buffer)) |s| {
- result.dynamic_linker_max = @intCast(u8, s.len - 1);
- }
+ result.dynamic_linker_max = result.target.standardDynamicLinkerPath(&result.dynamic_linker_buffer);
return result;
}
};
diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig
index 5358c4fedc..cd3f49edfa 100644
--- a/src-self-hosted/stage2.zig
+++ b/src-self-hosted/stage2.zig
@@ -1170,8 +1170,8 @@ fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8)
}
if (!have_native_dl) {
var buf: [255]u8 = undefined;
- dynamic_linker_ptr.* = if (adjusted_target.standardDynamicLinkerPath(&buf)) |s|
- try mem.dupeZ(std.heap.c_allocator, u8, s)
+ dynamic_linker_ptr.* = if (adjusted_target.standardDynamicLinkerPath(&buf)) |m|
+ try mem.dupeZ(std.heap.c_allocator, u8, buf[0 .. @as(usize, m) + 1])
else
null;
}
From 3683ba87ac5e5dfb6ea65c21c9fb714ed0582124 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 27 Feb 2020 19:49:00 -0500
Subject: [PATCH 26/62] complete the native target detection based on
/usr/bin/env
---
lib/std/c.zig | 1 +
lib/std/dynamic_library.zig | 4 +-
lib/std/elf.zig | 10 +-
lib/std/zig/system.zig | 306 ++++++++++++++++++++++++++++--------
4 files changed, 244 insertions(+), 77 deletions(-)
diff --git a/lib/std/c.zig b/lib/std/c.zig
index 9072d2c7cd..9d7d9524d6 100644
--- a/lib/std/c.zig
+++ b/lib/std/c.zig
@@ -108,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;
diff --git a/lib/std/dynamic_library.zig b/lib/std/dynamic_library.zig
index 34f45894fb..0d14f8d032 100644
--- a/lib/std/dynamic_library.zig
+++ b/lib/std/dynamic_library.zig
@@ -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]);
diff --git a/lib/std/elf.zig b/lib/std/elf.zig
index 007a01bb90..99084f1897 100644
--- a/lib/std/elf.zig
+++ b/lib/std/elf.zig
@@ -708,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,
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index e8c95f5125..fe2f4c7e04 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -238,16 +238,6 @@ pub const NativeTargetInfo = struct {
// 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 LdInfo = struct {
- ld_path_buffer: [255]u8,
- ld_path_max: u8,
- abi: Target.Abi,
-
- pub fn ldPath(self: *const @This()) []const u8 {
- const m: usize = self.ld_path_max;
- return self.ld_path_buffer[0 .. m + 1];
- }
- };
const all_abis = comptime blk: {
assert(@enumToInt(Target.Abi.none) == 0);
const fields = std.meta.fields(Target.Abi)[1..];
@@ -333,7 +323,7 @@ pub const NativeTargetInfo = struct {
// 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 abiAndDynamicLinkerFromUsrBinEnv(cpu, os) catch |err| switch (err) {
+ return abiAndDynamicLinkerFromUsrBinEnv(cpu, os, ld_info_list) catch |err| switch (err) {
error.FileSystem,
error.SystemResources,
error.SymLinkLoop,
@@ -343,8 +333,6 @@ pub const NativeTargetInfo = struct {
=> |e| return e,
error.UnableToReadElfFile,
- error.ElfNotADynamicExecutable,
- error.InvalidElfProgramHeaders,
error.InvalidElfClass,
error.InvalidElfVersion,
error.InvalidElfEndian,
@@ -373,6 +361,10 @@ pub const NativeTargetInfo = struct {
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-";
@@ -389,7 +381,11 @@ pub const NativeTargetInfo = struct {
};
}
- fn abiAndDynamicLinkerFromUsrBinEnv(cpu: Target.Cpu, os: Target.Os) !NativeTargetInfo {
+ fn abiAndDynamicLinkerFromUsrBinEnv(
+ cpu: Target.Cpu,
+ os: Target.Os,
+ ld_info_list: []const LdInfo,
+ ) !NativeTargetInfo {
const env_file = std.fs.openFileAbsoluteC("/usr/bin/env", .{}) catch |err| switch (err) {
error.NoSpaceLeft => unreachable,
error.NameTooLong => unreachable,
@@ -409,8 +405,7 @@ pub const NativeTargetInfo = struct {
else => |e| return e,
};
var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined;
- const hdr_bytes_len = try wrapRead(env_file.pread(&hdr_buf, 0));
- if (hdr_bytes_len < @sizeOf(elf.Elf32_Ehdr)) return error.InvalidElfFile;
+ _ = try preadFull(env_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;
@@ -430,7 +425,6 @@ pub const NativeTargetInfo = struct {
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);
- const shstrndx = elfInt(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx);
var result: NativeTargetInfo = .{
.target = .{
@@ -439,67 +433,234 @@ pub const NativeTargetInfo = struct {
.abi = Target.Abi.default(cpu.arch, os),
},
};
+ var rpath_offset: ?u64 = null; // Found inside PT_DYNAMIC
- const ph_total_size = std.math.mul(u32, phentsize, phnum) catch |err| switch (err) {
- error.Overflow => return error.InvalidElfProgramHeaders,
- };
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 reserve = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr);
- const read_byte_len = try wrapRead(env_file.pread(ph_buf[0 .. ph_buf.len - reserve], phoff));
- if (read_byte_len < phentsize) return error.ElfNotADynamicExecutable;
- var buf_i: usize = 0;
- while (buf_i < read_byte_len and 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(env_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;
- buf_i += phentsize;
+ ph_buf_i += phentsize;
}) {
- const ph32 = @ptrCast(*elf.Elf32_Phdr, @alignCast(@alignOf(elf.Elf32_Phdr), &ph_buf[buf_i]));
- const ph64 = @ptrCast(*elf.Elf64_Phdr, @alignCast(@alignOf(elf.Elf64_Phdr), &ph_buf[buf_i]));
+ 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 => {
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);
- var interp_buf: [255]u8 = undefined;
- if (p_filesz > interp_buf.len) return error.NameTooLong;
- var read_offset: usize = 0;
- while (true) {
- const len = try wrapRead(env_file.pread(
- interp_buf[read_offset .. p_filesz - read_offset],
- p_offset + read_offset,
- ));
- if (len == 0) return error.UnexpectedEndOfFile;
- read_offset += len;
- if (read_offset == p_filesz) break;
- }
+ if (p_filesz > result.dynamic_linker_buffer.len) return error.NameTooLong;
+ _ = try preadFull(env_file, result.dynamic_linker_buffer[0..p_filesz], p_offset, p_filesz);
// PT_INTERP includes a null byte in p_filesz.
- result.setDynamicLinker(interp_buf[0 .. p_filesz - 1]);
+ const len = p_filesz - 1;
+ // dynamic_linker_max is "max", not "len".
+ // We know it will fit in u8 because we check against dynamic_linker_buffer.len above.
+ result.dynamic_linker_max = @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.ldPath());
+ if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) {
+ result.target.abi = ld_info.abi;
+ break;
+ }
+ }
},
- elf.PT_DYNAMIC => {
- std.debug.warn("found PT_DYNAMIC\n", .{});
+ // We only need this for detecting glibc version.
+ elf.PT_DYNAMIC => if (Target.current.os.tag == .linux and result.target.isGnuLibC()) {
+ 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(
+ env_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()) {
+ 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(env_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(env_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(
+ env_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(env_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 wrapRead(res: std.os.ReadError!usize) !usize {
- return res 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,
- };
+ 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) !NativeTargetInfo {
@@ -513,20 +674,31 @@ pub const NativeTargetInfo = struct {
result.dynamic_linker_max = result.target.standardDynamicLinkerPath(&result.dynamic_linker_buffer);
return result;
}
-};
-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;
+ const LdInfo = struct {
+ ld_path_buffer: [255]u8,
+ ld_path_max: u8,
+ abi: Target.Abi,
+
+ pub fn ldPath(self: *const LdInfo) []const u8 {
+ const m: usize = self.ld_path_max;
+ return self.ld_path_buffer[0 .. m + 1];
}
- } else {
- if (need_bswap) {
- return @byteSwap(@TypeOf(int_32), int_32);
+ };
+
+ 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 {
- return int_32;
+ if (need_bswap) {
+ return @byteSwap(@TypeOf(int_32), int_32);
+ } else {
+ return int_32;
+ }
}
}
-}
+};
From d45ea4d89d7232fc4bcf56a5e088d7d6b5004ebb Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 28 Feb 2020 02:00:20 -0500
Subject: [PATCH 27/62] stage1: make get_native_target go through self-hosted
---
lib/std/special/init-exe/src/main.zig | 2 +-
lib/std/target.zig | 2 +-
src/main.cpp | 10 ++-
src/stage2.cpp | 100 ++++++++++++++++++++++++++
src/target.cpp | 100 --------------------------
src/target.hpp | 1 -
6 files changed, 110 insertions(+), 105 deletions(-)
diff --git a/lib/std/special/init-exe/src/main.zig b/lib/std/special/init-exe/src/main.zig
index 5f35540dc0..c6a70af56d 100644
--- a/lib/std/special/init-exe/src/main.zig
+++ b/lib/std/special/init-exe/src/main.zig
@@ -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", .{});
}
diff --git a/lib/std/target.zig b/lib/std/target.zig
index 379ae72afe..a72bd921b0 100644
--- a/lib/std/target.zig
+++ b/lib/std/target.zig
@@ -1215,8 +1215,8 @@ pub const Target = struct {
.uefi,
.windows,
.emscripten,
- .other,
.wasi,
+ .other,
=> return null,
// TODO go over each item in this list and either move it to the above list, or
diff --git a/src/main.cpp b/src/main.cpp
index 11612402ee..f741cafd40 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -500,7 +500,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))) {
+ 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);
@@ -1337,7 +1340,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))) {
+ 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);
diff --git a/src/stage2.cpp b/src/stage2.cpp
index 2023b45aaf..bc8e65fd56 100644
--- a/src/stage2.cpp
+++ b/src/stage2.cpp
@@ -91,6 +91,106 @@ 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){}
+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_version = heap::c_allocator.create();
+ target_init_default_glibc_version(target);
+ }
+}
+
Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu) {
Error err;
diff --git a/src/target.cpp b/src/target.cpp
index 8a68afbd83..4df2cfca85 100644
--- a/src/target.cpp
+++ b/src/target.cpp
@@ -287,83 +287,6 @@ ZigLLVM_OSType get_llvm_os_type(Os os_type) {
zig_unreachable();
}
-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();
-}
-
const char *target_os_name(Os os_type) {
switch (os_type) {
case OsFreestanding:
@@ -447,29 +370,6 @@ Error target_parse_glibc_version(ZigGLibCVersion *glibc_ver, const char *text) {
return ErrorNone;
}
-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_version = heap::c_allocator.create();
- target_init_default_glibc_version(target);
- }
-}
-
void target_init_default_glibc_version(ZigTarget *target) {
*target->glibc_version = {2, 17, 0};
}
diff --git a/src/target.hpp b/src/target.hpp
index 9396eb2623..e72b6a6f49 100644
--- a/src/target.hpp
+++ b/src/target.hpp
@@ -73,7 +73,6 @@ ZigLLVM_ObjectFormatType target_oformat_enum(size_t index);
const char *target_oformat_name(ZigLLVM_ObjectFormatType oformat);
ZigLLVM_ObjectFormatType target_object_format(const ZigTarget *target);
-void get_native_target(ZigTarget *target);
void target_triple_llvm(Buf *triple, const ZigTarget *target);
void target_triple_zig(Buf *triple, const ZigTarget *target);
From ef24f2dd93729493531c427aaac54444597f6e66 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 28 Feb 2020 02:36:16 -0500
Subject: [PATCH 28/62] remove special darwin os version min handling
now it is integrated with zig's target OS range.
---
lib/std/target.zig | 21 +++++-
lib/std/zig/cross_target.zig | 6 +-
src-self-hosted/stage2.zig | 39 +++++++----
src/all_types.hpp | 2 -
src/codegen.cpp | 59 +++-------------
src/codegen.hpp | 2 -
src/glibc.cpp | 26 +++----
src/glibc.hpp | 2 +-
src/link.cpp | 127 +++++------------------------------
src/main.cpp | 20 ------
src/stage2.cpp | 2 +-
src/stage2.h | 9 ++-
src/target.cpp | 4 +-
src/target.hpp | 2 +-
test/cli.zig | 2 +-
15 files changed, 95 insertions(+), 228 deletions(-)
diff --git a/lib/std/target.zig b/lib/std/target.zig
index a72bd921b0..6ecb679f29 100644
--- a/lib/std/target.zig
+++ b/lib/std/target.zig
@@ -147,7 +147,6 @@ pub const Target = struct {
.cloudabi,
.dragonfly,
.fuchsia,
- .ios,
.kfreebsd,
.lv2,
.solaris,
@@ -162,8 +161,6 @@ pub const Target = struct {
.amdhsa,
.ps4,
.elfiamcu,
- .tvos,
- .watchos,
.mesa3d,
.contiki,
.amdpal,
@@ -187,6 +184,24 @@ pub const Target = struct {
.max = .{ .major = 10, .minor = 15, .patch = 3 },
},
},
+ .ios => return .{
+ .semver = .{
+ .min = .{ .major = 12, .minor = 0 },
+ .max = .{ .major = 13, .minor = 4, .patch = 0 },
+ },
+ },
+ .watchos => return .{
+ .semver = .{
+ .min = .{ .major = 6, .minor = 0 },
+ .max = .{ .major = 6, .minor = 2, .patch = 0 },
+ },
+ },
+ .tvos => return .{
+ .semver = .{
+ .min = .{ .major = 13, .minor = 0 },
+ .max = .{ .major = 13, .minor = 4, .patch = 0 },
+ },
+ },
.netbsd => return .{
.semver = .{
.min = .{ .major = 8, .minor = 0 },
diff --git a/lib/std/zig/cross_target.zig b/lib/std/zig/cross_target.zig
index fac90ddba8..c7fd1f0464 100644
--- a/lib/std/zig/cross_target.zig
+++ b/lib/std/zig/cross_target.zig
@@ -88,7 +88,6 @@ pub const CrossTarget = struct {
.cloudabi,
.dragonfly,
.fuchsia,
- .ios,
.kfreebsd,
.lv2,
.solaris,
@@ -103,8 +102,6 @@ pub const CrossTarget = struct {
.amdhsa,
.ps4,
.elfiamcu,
- .tvos,
- .watchos,
.mesa3d,
.contiki,
.amdpal,
@@ -121,8 +118,11 @@ pub const CrossTarget = struct {
.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 };
diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig
index cd3f49edfa..3dae15056e 100644
--- a/src-self-hosted/stage2.zig
+++ b/src-self-hosted/stage2.zig
@@ -892,7 +892,7 @@ 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,
@@ -1103,16 +1103,29 @@ const Stage2Target = extern struct {
os_builtin_str_buffer.toSlice()[os_builtin_str_ver_start_index..os_builtin_str_buffer.len()],
);
- const glibc_version = if (target.isGnuLibC()) blk: {
- const stage1_glibc = try std.heap.c_allocator.create(Stage2GLibCVersion);
- 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 null;
+ 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.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch
@@ -1125,7 +1138,7 @@ const Stage2Target = extern struct {
.os_builtin_str = os_builtin_str_buffer.toOwnedSlice().ptr,
.cache_hash = cache_hash.toOwnedSlice().ptr,
.is_native = cross_target.isNative(),
- .glibc_version = glibc_version,
+ .glibc_or_darwin_version = glibc_or_darwin_version,
.dynamic_linker = dynamic_linker,
};
}
@@ -1179,7 +1192,7 @@ fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8)
}
// ABI warning
-const Stage2GLibCVersion = extern struct {
+const Stage2SemVer = extern struct {
major: u32,
minor: u32,
patch: u32,
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 7277d04359..838709b9c0 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2250,8 +2250,6 @@ 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;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 15122d5e11..8ae730616d 100644
--- a/src/codegen.cpp
+++ b/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();
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;
}
@@ -8655,10 +8622,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);
@@ -10313,10 +10280,10 @@ 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);
}
cache_int(ch, detect_subsystem(g));
cache_bool(ch, g->strip_debug_symbols);
@@ -10344,8 +10311,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);
@@ -10662,9 +10627,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;
@@ -10772,11 +10734,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)) {
diff --git a/src/codegen.hpp b/src/codegen.hpp
index 6329c59a5e..191da9a04b 100644
--- a/src/codegen.hpp
+++ b/src/codegen.hpp
@@ -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);
diff --git a/src/glibc.cpp b/src/glibc.cpp
index 91e2f9dfc1..da5c1d5290 100644
--- a/src/glibc.cpp
+++ b/src/glibc.cpp
@@ -55,7 +55,7 @@ Error glibc_load_metadata(ZigGLibCAbi **out_result, Buf *zig_lib_dir, bool verbo
Optional> 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);
diff --git a/src/glibc.hpp b/src/glibc.hpp
index 8e4c7888ad..c04dcb4629 100644
--- a/src/glibc.hpp
+++ b/src/glibc.hpp
@@ -32,7 +32,7 @@ struct ZigGLibCAbi {
Buf *abi_txt_path;
Buf *vers_txt_path;
Buf *fns_txt_path;
- ZigList all_versions;
+ ZigList all_versions;
ZigList all_functions;
// The value is a pointer to all_functions.length items and each item is an index
// into all_functions.
diff --git a/src/link.cpp b/src/link.cpp
index 901390feae..588771d8bf 100644
--- a/src/link.cpp
+++ b/src/link.cpp
@@ -2371,99 +2371,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;
@@ -2507,25 +2414,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");
diff --git a/src/main.cpp b/src/main.cpp
index f741cafd40..f471bda374 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -127,8 +127,6 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
" --subsystem [subsystem] (windows) /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"
@@ -414,8 +412,6 @@ 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;
ZigList rpath_list = {0};
@@ -844,10 +840,6 @@ 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) {
@@ -1240,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));
diff --git a/src/stage2.cpp b/src/stage2.cpp
index bc8e65fd56..67a518e1fa 100644
--- a/src/stage2.cpp
+++ b/src/stage2.cpp
@@ -186,7 +186,7 @@ static void get_native_target(ZigTarget *target) {
target->abi = target_default_abi(target->arch, target->os);
}
if (target_is_glibc(target)) {
- target->glibc_version = heap::c_allocator.create();
+ target->glibc_or_darwin_version = heap::c_allocator.create();
target_init_default_glibc_version(target);
}
}
diff --git a/src/stage2.h b/src/stage2.h
index 96222e3138..20311788b2 100644
--- a/src/stage2.h
+++ b/src/stage2.h
@@ -270,14 +270,12 @@ enum Os {
};
// ABI warning
-struct ZigGLibCVersion {
- uint32_t major; // always 2
+struct Stage2SemVer {
+ uint32_t major;
uint32_t minor;
uint32_t patch;
};
-struct Stage2TargetData;
-
// ABI warning
struct ZigTarget {
enum ZigLLVM_ArchType arch;
@@ -288,7 +286,8 @@ struct ZigTarget {
bool is_native;
- struct ZigGLibCVersion *glibc_version; // null means default
+ // null means default. this is double-purposed to be darwin min version
+ struct Stage2SemVer *glibc_or_darwin_version;
const char *llvm_cpu_name;
const char *llvm_cpu_features;
diff --git a/src/target.cpp b/src/target.cpp
index 4df2cfca85..96ac2e1666 100644
--- a/src/target.cpp
+++ b/src/target.cpp
@@ -347,7 +347,7 @@ const char *target_abi_name(ZigLLVM_EnvironmentType abi) {
return ZigLLVMGetEnvironmentTypeName(abi);
}
-Error target_parse_glibc_version(ZigGLibCVersion *glibc_ver, const char *text) {
+Error target_parse_glibc_version(Stage2SemVer *glibc_ver, const char *text) {
glibc_ver->major = 2;
glibc_ver->minor = 0;
glibc_ver->patch = 0;
@@ -371,7 +371,7 @@ Error target_parse_glibc_version(ZigGLibCVersion *glibc_ver, const char *text) {
}
void target_init_default_glibc_version(ZigTarget *target) {
- *target->glibc_version = {2, 17, 0};
+ *target->glibc_or_darwin_version = {2, 17, 0};
}
Error target_parse_arch(ZigLLVM_ArchType *out_arch, const char *arch_ptr, size_t arch_len) {
diff --git a/src/target.hpp b/src/target.hpp
index e72b6a6f49..9c6e8ce46e 100644
--- a/src/target.hpp
+++ b/src/target.hpp
@@ -46,7 +46,7 @@ Error target_parse_arch(ZigLLVM_ArchType *arch, const char *arch_ptr, size_t arc
Error target_parse_os(Os *os, const char *os_ptr, size_t os_len);
Error target_parse_abi(ZigLLVM_EnvironmentType *abi, const char *abi_ptr, size_t abi_len);
-Error target_parse_glibc_version(ZigGLibCVersion *out, const char *text);
+Error target_parse_glibc_version(Stage2SemVer *out, const char *text);
void target_init_default_glibc_version(ZigTarget *target);
size_t target_arch_count(void);
diff --git a/test/cli.zig b/test/cli.zig
index bc5a29be44..117c714a29 100644
--- a/test/cli.zig
+++ b/test/cli.zig
@@ -92,7 +92,7 @@ fn testZigInitLib(zig_exe: []const u8, dir_path: []const u8) !void {
fn testZigInitExe(zig_exe: []const u8, dir_path: []const u8) !void {
_ = try exec(dir_path, &[_][]const u8{ zig_exe, "init-exe" });
const run_result = try exec(dir_path, &[_][]const u8{ zig_exe, "build", "run" });
- testing.expect(std.mem.eql(u8, run_result.stderr, "All your base are belong to us.\n"));
+ testing.expect(std.mem.eql(u8, run_result.stderr, "All your codebase are belong to us.\n"));
}
fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void {
From 07f52119de2a8bdb84389c73332e113cf12ac997 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 28 Feb 2020 03:11:37 -0500
Subject: [PATCH 29/62] implement native OS version detection for linux
---
lib/std/c.zig | 1 +
lib/std/os.zig | 24 +++++++++++++-----------
lib/std/zig/system.zig | 17 ++++++++++++++++-
3 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/lib/std/c.zig b/lib/std/c.zig
index 9d7d9524d6..48a3039f51 100644
--- a/lib/std/c.zig
+++ b/lib/std/c.zig
@@ -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;
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 9f349e7dc4..49e88bf9c7 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -3295,22 +3295,24 @@ pub fn gethostname(name_buffer: *[HOST_NAME_MAX]u8) GetHostNameError![]u8 {
}
}
if (builtin.os.tag == .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),
- }
+ 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,
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index fe2f4c7e04..ffae5c6015 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -200,7 +200,22 @@ pub const NativeTargetInfo = struct {
const cpu = Target.Cpu.baseline(arch);
// TODO Detect native operating system version. Until that is implemented we use the default range.
- const os = Target.Os.defaultVersionRange(os_tag);
+ var os = Target.Os.defaultVersionRange(os_tag);
+ 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 => {},
+ }
+ },
+ else => {},
+ }
return detectAbiAndDynamicLinker(allocator, cpu, os);
}
From 500dde32d5cf59f5700fb3f69ae6c7a0defd8a93 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 28 Feb 2020 13:27:52 -0500
Subject: [PATCH 30/62] dynamic_linker becomes a field of std.zig.CrossTarget
---
lib/std/build.zig | 12 ++---
lib/std/target.zig | 92 +++++++++++++++++++++++++-----------
lib/std/zig/cross_target.zig | 17 +++++--
lib/std/zig/system.zig | 77 ++++++++++--------------------
src-self-hosted/stage2.zig | 15 +++---
src/all_types.hpp | 1 -
src/codegen.cpp | 19 ++------
src/link.cpp | 4 +-
src/main.cpp | 11 ++---
src/stage2.cpp | 7 ++-
src/stage2.h | 3 +-
src/target.cpp | 4 +-
src/target.hpp | 2 +-
13 files changed, 137 insertions(+), 127 deletions(-)
diff --git a/lib/std/build.zig b/lib/std/build.zig
index 7852828f7c..3ca59ae4cb 100644
--- a/lib/std/build.zig
+++ b/lib/std/build.zig
@@ -1177,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,
@@ -1978,6 +1976,11 @@ pub const LibExeObjStep = struct {
}
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| {
@@ -1985,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));
diff --git a/lib/std/target.zig b/lib/std/target.zig
index 6ecb679f29..3054c60467 100644
--- a/lib/std/target.zig
+++ b/lib/std/target.zig
@@ -1099,16 +1099,52 @@ pub const Target = struct {
}
}
+ pub const DynamicLinker = struct {
+ /// Contains the memory used to store the dynamic linker path. This field should
+ /// not be used directly. See `get` and `set`. This field exists so that this API requires no allocator.
+ buffer: [255]u8 = undefined,
+
+ /// Used to construct the dynamic linker path. This field should not be used
+ /// directly. See `get` and `set`.
+ max_byte: ?u8 = null,
+
+ /// Asserts that the length is less than or equal to 255 bytes.
+ pub fn init(dl_or_null: ?[]const u8) DynamicLinker {
+ var result: DynamicLinker = undefined;
+ result.set(dl_or_null);
+ return result;
+ }
+
+ /// The returned memory has the same lifetime as the `DynamicLinker`.
+ pub fn get(self: *const DynamicLinker) ?[]const u8 {
+ const m: usize = self.max_byte orelse return null;
+ return self.buffer[0 .. m + 1];
+ }
+
+ /// Asserts that the length is less than or equal to 255 bytes.
+ pub fn set(self: *DynamicLinker, dl_or_null: ?[]const u8) void {
+ if (dl_or_null) |dl| {
+ mem.copy(u8, &self.buffer, dl);
+ self.max_byte = @intCast(u8, dl.len - 1);
+ } else {
+ self.max_byte = null;
+ }
+ }
+ };
+
/// The result will be a byte index *pointing at the final byte*. In other words, length minus one.
/// A return value of `null` means the concept of a dynamic linker is not meaningful for that target.
- pub fn standardDynamicLinkerPath(self: Target, buffer: *[255]u8) ?u8 {
+ pub fn standardDynamicLinkerPath(self: Target) DynamicLinker {
+ var result: DynamicLinker = .{};
const S = struct {
- fn print(b: *[255]u8, comptime fmt: []const u8, args: var) u8 {
- return @intCast(u8, (std.fmt.bufPrint(b, fmt, args) catch unreachable).len - 1);
+ fn print(r: *DynamicLinker, comptime fmt: []const u8, args: var) DynamicLinker {
+ r.max_byte = @intCast(u8, (std.fmt.bufPrint(&r.buffer, fmt, args) catch unreachable).len - 1);
+ return r.*;
}
- fn copy(b: *[255]u8, s: []const u8) u8 {
- mem.copy(u8, b, s);
- return @intCast(u8, s.len - 1);
+ fn copy(r: *DynamicLinker, s: []const u8) DynamicLinker {
+ mem.copy(u8, &r.buffer, s);
+ r.max_byte = @intCast(u8, s.len - 1);
+ return r.*;
}
};
const print = S.print;
@@ -1116,7 +1152,7 @@ pub const Target = struct {
if (self.isAndroid()) {
const suffix = if (self.cpu.arch.ptrBitWidth() == 64) "64" else "";
- return print(buffer, "/system/bin/linker{}", .{suffix});
+ return print(&result, "/system/bin/linker{}", .{suffix});
}
if (self.isMusl()) {
@@ -1130,28 +1166,28 @@ pub const Target = struct {
else => |arch| @tagName(arch),
};
const arch_suffix = if (is_arm and self.getFloatAbi() == .hard) "hf" else "";
- return print(buffer, "/lib/ld-musl-{}{}.so.1", .{ arch_part, arch_suffix });
+ return print(&result, "/lib/ld-musl-{}{}.so.1", .{ arch_part, arch_suffix });
}
switch (self.os.tag) {
- .freebsd => return copy(buffer, "/libexec/ld-elf.so.1"),
- .netbsd => return copy(buffer, "/libexec/ld.elf_so"),
- .dragonfly => return copy(buffer, "/libexec/ld-elf.so.2"),
+ .freebsd => return copy(&result, "/libexec/ld-elf.so.1"),
+ .netbsd => return copy(&result, "/libexec/ld.elf_so"),
+ .dragonfly => return copy(&result, "/libexec/ld-elf.so.2"),
.linux => switch (self.cpu.arch) {
.i386,
.sparc,
.sparcel,
- => return copy(buffer, "/lib/ld-linux.so.2"),
+ => return copy(&result, "/lib/ld-linux.so.2"),
- .aarch64 => return copy(buffer, "/lib/ld-linux-aarch64.so.1"),
- .aarch64_be => return copy(buffer, "/lib/ld-linux-aarch64_be.so.1"),
- .aarch64_32 => return copy(buffer, "/lib/ld-linux-aarch64_32.so.1"),
+ .aarch64 => return copy(&result, "/lib/ld-linux-aarch64.so.1"),
+ .aarch64_be => return copy(&result, "/lib/ld-linux-aarch64_be.so.1"),
+ .aarch64_32 => return copy(&result, "/lib/ld-linux-aarch64_32.so.1"),
.arm,
.armeb,
.thumb,
.thumbeb,
- => return copy(buffer, switch (self.getFloatAbi()) {
+ => return copy(&result, switch (self.getFloatAbi()) {
.hard => "/lib/ld-linux-armhf.so.3",
else => "/lib/ld-linux.so.3",
}),
@@ -1168,20 +1204,20 @@ pub const Target = struct {
};
const is_nan_2008 = mips.featureSetHas(self.cpu.features, .nan2008);
const loader = if (is_nan_2008) "ld-linux-mipsn8.so.1" else "ld.so.1";
- return print(buffer, "/lib{}/{}", .{ lib_suffix, loader });
+ return print(&result, "/lib{}/{}", .{ lib_suffix, loader });
},
- .powerpc => return copy(buffer, "/lib/ld.so.1"),
- .powerpc64, .powerpc64le => return copy(buffer, "/lib64/ld64.so.2"),
- .s390x => return copy(buffer, "/lib64/ld64.so.1"),
- .sparcv9 => return copy(buffer, "/lib64/ld-linux.so.2"),
- .x86_64 => return copy(buffer, switch (self.abi) {
+ .powerpc => return copy(&result, "/lib/ld.so.1"),
+ .powerpc64, .powerpc64le => return copy(&result, "/lib64/ld64.so.2"),
+ .s390x => return copy(&result, "/lib64/ld64.so.1"),
+ .sparcv9 => return copy(&result, "/lib64/ld-linux.so.2"),
+ .x86_64 => return copy(&result, switch (self.abi) {
.gnux32 => "/libx32/ld-linux-x32.so.2",
else => "/lib64/ld-linux-x86-64.so.2",
}),
- .riscv32 => return copy(buffer, "/lib/ld-linux-riscv32-ilp32.so.1"),
- .riscv64 => return copy(buffer, "/lib/ld-linux-riscv64-lp64.so.1"),
+ .riscv32 => return copy(&result, "/lib/ld-linux-riscv32-ilp32.so.1"),
+ .riscv64 => return copy(&result, "/lib/ld-linux-riscv64-lp64.so.1"),
// Architectures in this list have been verified as not having a standard
// dynamic linker path.
@@ -1191,7 +1227,7 @@ pub const Target = struct {
.bpfeb,
.nvptx,
.nvptx64,
- => return null,
+ => return result,
// TODO go over each item in this list and either move it to the above list, or
// implement the standard dynamic linker path code for it.
@@ -1217,7 +1253,7 @@ pub const Target = struct {
.lanai,
.renderscript32,
.renderscript64,
- => return null,
+ => return result,
},
// Operating systems in this list have been verified as not having a standard
@@ -1232,7 +1268,7 @@ pub const Target = struct {
.emscripten,
.wasi,
.other,
- => return null,
+ => return result,
// TODO go over each item in this list and either move it to the above list, or
// implement the standard dynamic linker path code for it.
@@ -1259,7 +1295,7 @@ pub const Target = struct {
.amdpal,
.hermit,
.hurd,
- => return null,
+ => return result,
}
}
};
diff --git a/lib/std/zig/cross_target.zig b/lib/std/zig/cross_target.zig
index c7fd1f0464..212bc8eb9a 100644
--- a/lib/std/zig/cross_target.zig
+++ b/lib/std/zig/cross_target.zig
@@ -40,6 +40,10 @@ pub const CrossTarget = struct {
/// If `isGnuLibC()` is `false`, this must be `null` and is ignored.
glibc_version: ?SemVer = 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 OsVersion = union(enum) {
none: void,
semver: SemVer,
@@ -48,6 +52,8 @@ pub const CrossTarget = struct {
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,
@@ -170,6 +176,10 @@ pub const CrossTarget = struct {
/// 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,
@@ -199,8 +209,9 @@ pub const CrossTarget = struct {
var dummy_diags: ParseOptions.Diagnostics = undefined;
const diags = args.diagnostics orelse &dummy_diags;
- // Start with everything initialized to default values.
- var result: CrossTarget = .{};
+ var result: CrossTarget = .{
+ .dynamic_linker = DynamicLinker.init(args.dynamic_linker),
+ };
var it = mem.separate(args.arch_os_abi, "-");
const arch_name = it.next().?;
@@ -446,7 +457,7 @@ pub const CrossTarget = struct {
return self.cpu_arch == null and self.cpu_model == null 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;
+ self.abi == null and self.dynamic_linker.get() == null;
}
pub fn zigTriple(self: CrossTarget, allocator: *mem.Allocator) error{OutOfMemory}![:0]u8 {
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index ffae5c6015..44ff9af674 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -168,14 +168,9 @@ pub const NativePaths = struct {
pub const NativeTargetInfo = struct {
target: Target,
- /// Contains the memory used to store the dynamic linker path. This field should
- /// not be used directly. See `dynamicLinker` and `setDynamicLinker`. This field
- /// exists so that this API requires no allocator.
- dynamic_linker_buffer: [255]u8 = undefined,
+ dynamic_linker: DynamicLinker = DynamicLinker{},
- /// Used to construct the dynamic linker path. This field should not be used
- /// directly. See `dynamicLinker` and `setDynamicLinker`.
- dynamic_linker_max: ?u8 = null,
+ pub const DynamicLinker = Target.DynamicLinker;
pub const DetectError = error{
OutOfMemory,
@@ -220,21 +215,6 @@ pub const NativeTargetInfo = struct {
return detectAbiAndDynamicLinker(allocator, cpu, os);
}
- /// The returned memory has the same lifetime as the `NativeTargetInfo`.
- pub fn dynamicLinker(self: *const NativeTargetInfo) ?[]const u8 {
- const m: usize = self.dynamic_linker_max orelse return null;
- return self.dynamic_linker_buffer[0 .. m + 1];
- }
-
- pub fn setDynamicLinker(self: *NativeTargetInfo, dl_or_null: ?[]const u8) void {
- if (dl_or_null) |dl| {
- mem.copy(u8, &self.dynamic_linker_buffer, dl);
- self.dynamic_linker_max = @intCast(u8, dl.len - 1);
- } else {
- self.dynamic_linker_max = null;
- }
- }
-
/// 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
@@ -273,15 +253,14 @@ pub const NativeTargetInfo = struct {
.os = os,
.abi = abi,
};
- const ld_info = &ld_info_list_buffer[ld_info_list_len];
- ld_info_list_len += 1;
+ const ld = target.standardDynamicLinkerPath();
+ if (ld.get() == null) continue;
- ld_info.* = .{
- .ld_path_buffer = undefined,
- .ld_path_max = undefined,
+ ld_info_list_buffer[ld_info_list_len] = .{
+ .ld = ld,
.abi = abi,
};
- ld_info.ld_path_max = target.standardDynamicLinkerPath(&ld_info.ld_path_buffer) orelse continue;
+ ld_info_list_len += 1;
}
const ld_info_list = ld_info_list_buffer[0..ld_info_list_len];
@@ -298,7 +277,7 @@ pub const NativeTargetInfo = struct {
// 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.ldPath());
+ 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;
@@ -329,8 +308,8 @@ pub const NativeTargetInfo = struct {
.os = os_adjusted,
.abi = found_ld_info.abi,
},
+ .dynamic_linker = DynamicLinker.init(found_ld_path),
};
- result.setDynamicLinker(found_ld_path);
return result;
}
@@ -472,18 +451,18 @@ pub const NativeTargetInfo = struct {
elf.PT_INTERP => {
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(env_file, result.dynamic_linker_buffer[0..p_filesz], p_offset, p_filesz);
+ if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong;
+ _ = try preadFull(env_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 is "max", not "len".
- // We know it will fit in u8 because we check against dynamic_linker_buffer.len above.
- result.dynamic_linker_max = @intCast(u8, len - 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];
+ 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.ldPath());
+ 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;
@@ -679,26 +658,20 @@ pub const NativeTargetInfo = struct {
}
fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os) !NativeTargetInfo {
- var result: NativeTargetInfo = .{
- .target = .{
- .cpu = cpu,
- .os = os,
- .abi = Target.Abi.default(cpu.arch, os),
- },
+ const target: Target = .{
+ .cpu = cpu,
+ .os = os,
+ .abi = Target.Abi.default(cpu.arch, os),
+ };
+ return NativeTargetInfo{
+ .target = target,
+ .dynamic_linker = target.standardDynamicLinkerPath(),
};
- result.dynamic_linker_max = result.target.standardDynamicLinkerPath(&result.dynamic_linker_buffer);
- return result;
}
const LdInfo = struct {
- ld_path_buffer: [255]u8,
- ld_path_max: u8,
+ ld: DynamicLinker,
abi: Target.Abi,
-
- pub fn ldPath(self: *const LdInfo) []const u8 {
- const m: usize = self.ld_path_max;
- return self.ld_path_buffer[0 .. m + 1];
- }
};
fn elfInt(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_64) {
diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig
index 3dae15056e..726c65937e 100644
--- a/src-self-hosted/stage2.zig
+++ b/src-self-hosted/stage2.zig
@@ -651,8 +651,9 @@ 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,
@@ -676,14 +677,17 @@ 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: 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 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.UnknownCpuModel => {
@@ -1170,7 +1174,7 @@ fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8)
if (cross_target.os_tag == null) {
adjusted_target.os = detected_info.target.os;
- if (detected_info.dynamicLinker()) |dl| {
+ if (detected_info.dynamic_linker.get()) |dl| {
have_native_dl = true;
dynamic_linker_ptr.* = try mem.dupeZ(std.heap.c_allocator, u8, dl);
}
@@ -1182,11 +1186,8 @@ fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8)
}
}
if (!have_native_dl) {
- var buf: [255]u8 = undefined;
- dynamic_linker_ptr.* = if (adjusted_target.standardDynamicLinkerPath(&buf)) |m|
- try mem.dupeZ(std.heap.c_allocator, u8, buf[0 .. @as(usize, m) + 1])
- else
- null;
+ const dl = adjusted_target.standardDynamicLinkerPath();
+ dynamic_linker_ptr.* = if (dl.get()) |s| try mem.dupeZ(std.heap.c_allocator, u8, s) else null;
}
return adjusted_target;
}
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 838709b9c0..9f6bfd80a5 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2255,7 +2255,6 @@ struct CodeGen {
Buf *test_name_prefix;
Buf *zig_lib_dir;
Buf *zig_std_dir;
- Buf *dynamic_linker_path;
Buf *version_script_path;
const char **llvm_argv;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 8ae730616d..62f2c7a8ba 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -8832,19 +8832,6 @@ static void init(CodeGen *g) {
}
}
-static void detect_dynamic_linker(CodeGen *g) {
- 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;
-
- if (g->zig_target->dynamic_linker != nullptr) {
- g->dynamic_linker_path = buf_create_from_str(g->zig_target->dynamic_linker);
- }
-}
-
static void detect_libc(CodeGen *g) {
Error err;
@@ -10285,6 +10272,9 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
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);
cache_bool(ch, g->is_test_build);
@@ -10325,7 +10315,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
@@ -10422,7 +10411,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) {
@@ -10619,7 +10607,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;
diff --git a/src/link.cpp b/src/link.cpp
index 588771d8bf..03534db3b2 100644
--- a/src/link.cpp
+++ b/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);
}
}
diff --git a/src/main.cpp b/src/main.cpp
index f471bda374..92d08bed4f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -401,7 +401,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 clang_argv = {0};
ZigList lib_dirs = {0};
@@ -496,7 +496,7 @@ 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;
- if ((err = target_parse_triple(&target, "native", nullptr))) {
+ if ((err = target_parse_triple(&target, "native", nullptr, nullptr))) {
fprintf(stderr, "Unable to get native target: %s\n", err_str(err));
return EXIT_FAILURE;
}
@@ -766,7 +766,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) {
@@ -968,7 +968,7 @@ 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);
@@ -1193,7 +1193,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;
@@ -1320,7 +1319,7 @@ static int main0(int argc, char **argv) {
return main_exit(root_progress_node, EXIT_SUCCESS);
} else if (cmd == CmdTest) {
ZigTarget native;
- if ((err = target_parse_triple(&native, "native", nullptr))) {
+ if ((err = target_parse_triple(&native, "native", nullptr, nullptr))) {
fprintf(stderr, "Unable to get native target: %s\n", err_str(err));
return EXIT_FAILURE;
}
diff --git a/src/stage2.cpp b/src/stage2.cpp
index 67a518e1fa..1f6cb2d6aa 100644
--- a/src/stage2.cpp
+++ b/src/stage2.cpp
@@ -191,7 +191,9 @@ static void get_native_target(ZigTarget *target) {
}
}
-Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu) {
+Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu,
+ const char *dynamic_linker)
+{
Error err;
if (zig_triple == nullptr) {
@@ -249,6 +251,9 @@ Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, cons
target->cache_hash = "\n\n";
}
+ if (dynamic_linker != nullptr) {
+ target->dynamic_linker = dynamic_linker;
+ }
return ErrorNone;
}
diff --git a/src/stage2.h b/src/stage2.h
index 20311788b2..b73269f4e8 100644
--- a/src/stage2.h
+++ b/src/stage2.h
@@ -298,7 +298,8 @@ struct ZigTarget {
};
// ABI warning
-ZIG_EXTERN_C enum Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu);
+ZIG_EXTERN_C enum Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu,
+ const char *dynamic_linker);
// ABI warning
diff --git a/src/target.cpp b/src/target.cpp
index 96ac2e1666..f0030e05ac 100644
--- a/src/target.cpp
+++ b/src/target.cpp
@@ -410,8 +410,8 @@ Error target_parse_abi(ZigLLVM_EnvironmentType *out_abi, const char *abi_ptr, si
return ErrorUnknownABI;
}
-Error target_parse_triple(ZigTarget *target, const char *triple, const char *mcpu) {
- return stage2_target_parse(target, triple, mcpu);
+Error target_parse_triple(ZigTarget *target, const char *triple, const char *mcpu, const char *dynamic_linker) {
+ return stage2_target_parse(target, triple, mcpu, dynamic_linker);
}
const char *target_arch_name(ZigLLVM_ArchType arch) {
diff --git a/src/target.hpp b/src/target.hpp
index 9c6e8ce46e..01f2c6b168 100644
--- a/src/target.hpp
+++ b/src/target.hpp
@@ -41,7 +41,7 @@ enum CIntType {
CIntTypeCount,
};
-Error target_parse_triple(ZigTarget *target, const char *triple, const char *mcpu);
+Error target_parse_triple(ZigTarget *target, const char *triple, const char *mcpu, const char *dynamic_linker);
Error target_parse_arch(ZigLLVM_ArchType *arch, const char *arch_ptr, size_t arch_len);
Error target_parse_os(Os *os, const char *os_ptr, size_t os_len);
Error target_parse_abi(ZigLLVM_EnvironmentType *abi, const char *abi_ptr, size_t abi_len);
From 578dc16910c7fb6c9e3a059915b13fa6609e066f Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 28 Feb 2020 15:41:30 -0500
Subject: [PATCH 31/62] fix compiler crash when comptime parsing targets
---
src/analyze.cpp | 39 ++++++++++++++++++++++++++++++---------
1 file changed, 30 insertions(+), 9 deletions(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 2c8244d053..90037a1191 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -5401,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();
@@ -6701,8 +6703,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)
{
@@ -9390,13 +9400,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(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(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) {
From bee4007ec9a353b027654ccb4beeaf3d04dfa26f Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 28 Feb 2020 15:49:19 -0500
Subject: [PATCH 32/62] fix crash with multiple comptime fn calls and...
...default initialized array to undefined
closes #4578
---
src/analyze.cpp | 39 +++++++++++++++++++++++++++--------
test/stage1/behavior/eval.zig | 25 ++++++++++++++++++++++
2 files changed, 55 insertions(+), 9 deletions(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 9b776da930..98a93d03bb 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -5429,6 +5429,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) {
@@ -6701,8 +6703,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)
{
@@ -9398,13 +9408,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(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(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) {
diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig
index 8e70e97aaa..55ace6198c 100644
--- a/test/stage1/behavior/eval.zig
+++ b/test/stage1/behavior/eval.zig
@@ -807,3 +807,28 @@ test "return 0 from function that has u0 return type" {
}
}
}
+
+test "two comptime calls with array default initialized to undefined" {
+ const S = struct {
+ const CrossTarget = struct {
+ dynamic_linker: DynamicLinker = DynamicLinker{},
+
+ pub fn parse() void {
+ var result: CrossTarget = .{ };
+ result.getCpuArch();
+ }
+
+ pub fn getCpuArch(self: CrossTarget) void { }
+ };
+
+ const DynamicLinker = struct {
+ buffer: [255]u8 = undefined,
+ };
+
+ };
+
+ comptime {
+ S.CrossTarget.parse();
+ S.CrossTarget.parse();
+ }
+}
From a5a53a182af3715edd9474fe94cad2223a6c7fb9 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 28 Feb 2020 16:06:06 -0500
Subject: [PATCH 33/62] fix typo from other commit
d2535c003c6188fcc362028e01ef9f7fb3356727
---
src/analyze.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 98a93d03bb..55e65ae2a1 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -1135,7 +1135,7 @@ Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent
// 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.unionation.resolve_loop_flag_zero_bits)
+ !ty->data.pointer.resolve_loop_flag_zero_bits)
{
ty = ty->data.pointer.child_type;
}
From 8691d3c50d65c3e9e399c83cf2fc1a1173acb6d2 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 28 Feb 2020 17:23:16 -0500
Subject: [PATCH 34/62] improve std.zig.system.NativeTargetInfo.detect
It now takes a std.zig.CrossTarget parameter, and only resolves
native things, leaving explicitly overridden things alone.
---
lib/std/zig/cross_target.zig | 18 ++--
lib/std/zig/system.zig | 154 ++++++++++++++++++++++++++---------
src-self-hosted/stage2.zig | 50 ++++--------
3 files changed, 141 insertions(+), 81 deletions(-)
diff --git a/lib/std/zig/cross_target.zig b/lib/std/zig/cross_target.zig
index 212bc8eb9a..7ce35a26dc 100644
--- a/lib/std/zig/cross_target.zig
+++ b/lib/std/zig/cross_target.zig
@@ -7,19 +7,17 @@ const mem = std.mem;
/// 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.
+ /// `null` means native. If this is `null` then `cpu_model` must be `null`.
cpu_arch: ?Target.Cpu.Arch = null,
- /// If `cpu_arch` is native, `null` means native. Otherwise it means baseline.
+ /// `null` means native.
/// If this is non-null, `cpu_arch` must be specified.
cpu_model: ?*const Target.Cpu.Model = null,
/// Sparse set of CPU features to add to the set from `cpu_model`.
- /// If this is non-empty, `cpu_arch` must be specified.
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`.
- /// If this is non-empty, `cpu_arch` must be specified.
cpu_features_sub: Target.Cpu.Feature.Set = Target.Cpu.Feature.Set.empty,
/// `null` means native.
@@ -33,13 +31,13 @@ pub const CrossTarget = struct {
/// When `os_tag` is native, `null` means equal to the native OS version.
os_version_max: ?OsVersion = null,
- /// `null` means the native C ABI, if `os_tag` is native, otherwise it means the default C ABI.
- abi: ?Target.Abi = 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{},
@@ -146,6 +144,7 @@ pub const CrossTarget = struct {
}
}
+ /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
pub fn toTarget(self: CrossTarget) Target {
return .{
.cpu = self.getCpu(),
@@ -307,6 +306,7 @@ pub const CrossTarget = struct {
return result;
}
+ /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
pub fn getCpu(self: CrossTarget) Target.Cpu {
if (self.cpu_arch) |arch| {
if (self.cpu_model) |model| {
@@ -342,6 +342,7 @@ pub const CrossTarget = struct {
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
@@ -378,6 +379,7 @@ pub const CrossTarget = struct {
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;
@@ -385,6 +387,7 @@ pub const CrossTarget = struct {
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;
@@ -392,6 +395,7 @@ pub const CrossTarget = struct {
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;
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index 44ff9af674..f31044b811 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -7,6 +7,7 @@ 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 = Target.current.os.tag == .windows;
@@ -182,37 +183,87 @@ pub const NativeTargetInfo = struct {
DeviceBusy,
};
- /// Detects the native CPU model & features, operating system & version, and C ABI & dynamic linker.
- /// On Linux, this is additionally responsible for detecting the native glibc version when applicable.
+ /// 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) DetectError!NativeTargetInfo {
- const arch = Target.current.cpu.arch;
- const os_tag = Target.current.os.tag;
-
- // TODO Detect native CPU model & features. Until that is implemented we hard code baseline.
- const cpu = Target.Cpu.baseline(arch);
-
- // TODO Detect native operating system version. Until that is implemented we use the default range.
- var os = Target.Os.defaultVersionRange(os_tag);
- 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 => {},
+ pub fn detect(allocator: *Allocator, cross_target: CrossTarget) DetectError!NativeTargetInfo {
+ const cpu = blk: {
+ if (cross_target.cpu_arch) |arch| {
+ if (cross_target.cpu_model) |model| {
+ var adjusted_model = model.toCpu(arch);
+ cross_target.updateCpuFeatures(&adjusted_model.features);
+ break :blk adjusted_model;
+ } else {
+ // TODO Detect native CPU model. Until that is implemented we use baseline.
+ var adjusted_baseline = Target.Cpu.baseline(arch);
+ cross_target.updateCpuFeatures(&adjusted_baseline.features);
+ break :blk adjusted_baseline;
}
- },
- else => {},
+ } else {
+ assert(cross_target.cpu_model == null);
+ // TODO Detect native CPU model & features. Until that is implemented we use baseline.
+ var adjusted_baseline = Target.Cpu.baseline(Target.current.cpu.arch);
+ cross_target.updateCpuFeatures(&adjusted_baseline.features);
+ break :blk adjusted_baseline;
+ }
+ };
+
+ 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 => {
+ // TODO Detect native operating system version.
+ },
+ .macosx => {
+ // TODO Detect native operating system version.
+ },
+ .freebsd => {
+ // TODO Detect native operating system version.
+ },
+ else => {},
+ }
}
- return detectAbiAndDynamicLinker(allocator, cpu, os);
+ 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
@@ -224,9 +275,14 @@ pub const NativeTargetInfo = struct {
allocator: *Allocator,
cpu: Target.Cpu,
os: Target.Os,
+ cross_target: CrossTarget,
) DetectError!NativeTargetInfo {
- if (!comptime Target.current.hasDynamicLinker()) {
- return defaultAbiAndDynamicLinker(cpu, os);
+ 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());
+ if (!native_target_has_ld or have_all_info) {
+ 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.
@@ -264,6 +320,13 @@ pub const NativeTargetInfo = struct {
}
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: {
@@ -288,7 +351,9 @@ pub const NativeTargetInfo = struct {
// Look for glibc version.
var os_adjusted = os;
- if (Target.current.os.tag == .linux and found_ld_info.abi.isGnu()) {
+ 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) {
@@ -306,9 +371,12 @@ pub const NativeTargetInfo = struct {
.target = .{
.cpu = cpu,
.os = os_adjusted,
- .abi = found_ld_info.abi,
+ .abi = cross_target.abi orelse found_ld_info.abi,
},
- .dynamic_linker = DynamicLinker.init(found_ld_path),
+ .dynamic_linker = if (cross_target.dynamic_linker.get() == null)
+ DynamicLinker.init(found_ld_path)
+ else
+ cross_target.dynamic_linker,
};
return result;
}
@@ -317,7 +385,7 @@ pub const NativeTargetInfo = struct {
// 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 abiAndDynamicLinkerFromUsrBinEnv(cpu, os, ld_info_list) catch |err| switch (err) {
+ return abiAndDynamicLinkerFromUsrBinEnv(cpu, os, ld_info_list, cross_target) catch |err| switch (err) {
error.FileSystem,
error.SystemResources,
error.SymLinkLoop,
@@ -337,7 +405,7 @@ pub const NativeTargetInfo = struct {
error.UnexpectedEndOfFile,
error.NameTooLong,
// Finally, we fall back on the standard path.
- => defaultAbiAndDynamicLinker(cpu, os),
+ => defaultAbiAndDynamicLinker(cpu, os, cross_target),
};
}
@@ -379,6 +447,7 @@ pub const NativeTargetInfo = struct {
cpu: Target.Cpu,
os: Target.Os,
ld_info_list: []const LdInfo,
+ cross_target: CrossTarget,
) !NativeTargetInfo {
const env_file = std.fs.openFileAbsoluteC("/usr/bin/env", .{}) catch |err| switch (err) {
error.NoSpaceLeft => unreachable,
@@ -424,10 +493,12 @@ pub const NativeTargetInfo = struct {
.target = .{
.cpu = cpu,
.os = os,
- .abi = Target.Abi.default(cpu.arch, 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;
@@ -448,7 +519,7 @@ pub const NativeTargetInfo = struct {
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 => {
+ 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;
@@ -470,7 +541,9 @@ pub const NativeTargetInfo = struct {
}
},
// We only need this for detecting glibc version.
- elf.PT_DYNAMIC => if (Target.current.os.tag == .linux and result.target.isGnuLibC()) {
+ 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);
@@ -515,7 +588,7 @@ pub const NativeTargetInfo = struct {
}
}
- if (Target.current.os.tag == .linux and result.target.isGnuLibC()) {
+ 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);
@@ -657,15 +730,18 @@ pub const NativeTargetInfo = struct {
return i;
}
- fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os) !NativeTargetInfo {
+ fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, cross_target: CrossTarget) !NativeTargetInfo {
const target: Target = .{
.cpu = cpu,
.os = os,
- .abi = Target.Abi.default(cpu.arch, os),
+ .abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os),
};
return NativeTargetInfo{
.target = target,
- .dynamic_linker = target.standardDynamicLinkerPath(),
+ .dynamic_linker = if (cross_target.dynamic_linker.get() == null)
+ target.standardDynamicLinkerPath()
+ else
+ cross_target.dynamic_linker,
};
}
diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig
index 726c65937e..bef13a08e9 100644
--- a/src-self-hosted/stage2.zig
+++ b/src-self-hosted/stage2.zig
@@ -1152,44 +1152,24 @@ fn enumInt(comptime Enum: type, int: c_int) Enum {
return @intToEnum(Enum, @intCast(@TagType(Enum), int));
}
-/// TODO move dynamic linker to be part of the target
-/// TODO self-host this function
fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8) !Target {
- var adjusted_target = cross_target.toTarget();
- var have_native_dl = false;
- if (cross_target.cpu_arch == null or cross_target.os_tag == null) {
- const detected_info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator);
- if (cross_target.cpu_arch == null) {
- adjusted_target.cpu = detected_info.target.cpu;
-
- // TODO We want to just use detected_info.target but implementing
- // CPU model & feature detection is todo so here we rely on LLVM.
- // There is another occurrence of this; search for detectNativeCpuWithLLVM.
- const llvm = @import("llvm.zig");
- const llvm_cpu_name = llvm.GetHostCPUName();
- const llvm_cpu_features = llvm.GetNativeFeatures();
- const arch = std.Target.current.cpu.arch;
- adjusted_target.cpu = try detectNativeCpuWithLLVM(arch, llvm_cpu_name, llvm_cpu_features);
- }
- if (cross_target.os_tag == null) {
- adjusted_target.os = detected_info.target.os;
-
- if (detected_info.dynamic_linker.get()) |dl| {
- have_native_dl = true;
- dynamic_linker_ptr.* = try mem.dupeZ(std.heap.c_allocator, u8, dl);
- }
- if (cross_target.abi == null) {
- adjusted_target.abi = detected_info.target.abi;
- }
- } else if (cross_target.abi == null) {
- adjusted_target.abi = Target.Abi.default(adjusted_target.cpu.arch, adjusted_target.os);
- }
+ 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 == null) {
+ // 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);
}
- if (!have_native_dl) {
- const dl = adjusted_target.standardDynamicLinkerPath();
- dynamic_linker_ptr.* = if (dl.get()) |s| try mem.dupeZ(std.heap.c_allocator, u8, s) else null;
+ if (info.dynamic_linker.get()) |dl| {
+ dynamic_linker_ptr.* = try mem.dupeZ(std.heap.c_allocator, u8, dl);
+ } else {
+ dynamic_linker_ptr.* = null;
}
- return adjusted_target;
+ return info.target;
}
// ABI warning
From aa13f339d4d91f8e39f005821c172290e1a0227f Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 28 Feb 2020 18:09:33 -0500
Subject: [PATCH 35/62] fix handling of CrossTarget.cpu_model
---
lib/std/zig/cross_target.zig | 16 ++++++++++++++--
lib/std/zig/system.zig | 19 ++++++-------------
src-self-hosted/stage2.zig | 1 +
3 files changed, 21 insertions(+), 15 deletions(-)
diff --git a/lib/std/zig/cross_target.zig b/lib/std/zig/cross_target.zig
index 7ce35a26dc..a2d265707b 100644
--- a/lib/std/zig/cross_target.zig
+++ b/lib/std/zig/cross_target.zig
@@ -10,8 +10,7 @@ pub const CrossTarget = struct {
/// `null` means native. If this is `null` then `cpu_model` must be `null`.
cpu_arch: ?Target.Cpu.Arch = null,
- /// `null` means native.
- /// If this is non-null, `cpu_arch` must be specified.
+ /// `null` means native. If this is non-null, `cpu_arch` must be specified.
cpu_model: ?*const Target.Cpu.Model = null,
/// Sparse set of CPU features to add to the set from `cpu_model`.
@@ -301,6 +300,10 @@ pub const CrossTarget = struct {
return error.UnknownCpuFeature;
}
}
+ } else if (arch_is_native) {
+ result.cpu_model = null;
+ } else {
+ result.cpu_model = Target.Cpu.Model.baseline(arch);
}
return result;
@@ -725,6 +728,15 @@ pub const CrossTarget = struct {
};
test "CrossTarget.parse" {
+ {
+ 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 == null);
+ }
{
const cross_target = try CrossTarget.parse(.{ .arch_os_abi = "native" });
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index f31044b811..b712c7c062 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -192,21 +192,14 @@ pub const NativeTargetInfo = struct {
/// TODO Remove the Allocator requirement from this function.
pub fn detect(allocator: *Allocator, cross_target: CrossTarget) DetectError!NativeTargetInfo {
const cpu = blk: {
- if (cross_target.cpu_arch) |arch| {
- if (cross_target.cpu_model) |model| {
- var adjusted_model = model.toCpu(arch);
- cross_target.updateCpuFeatures(&adjusted_model.features);
- break :blk adjusted_model;
- } else {
- // TODO Detect native CPU model. Until that is implemented we use baseline.
- var adjusted_baseline = Target.Cpu.baseline(arch);
- cross_target.updateCpuFeatures(&adjusted_baseline.features);
- break :blk adjusted_baseline;
- }
+ const arch = cross_target.getCpuArch();
+ if (cross_target.cpu_model) |model| {
+ var adjusted_model = model.toCpu(arch);
+ cross_target.updateCpuFeatures(&adjusted_model.features);
+ break :blk adjusted_model;
} else {
- assert(cross_target.cpu_model == null);
// TODO Detect native CPU model & features. Until that is implemented we use baseline.
- var adjusted_baseline = Target.Cpu.baseline(Target.current.cpu.arch);
+ var adjusted_baseline = Target.Cpu.baseline(arch);
cross_target.updateCpuFeatures(&adjusted_baseline.features);
break :blk adjusted_baseline;
}
diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig
index bef13a08e9..696d7ea760 100644
--- a/src-self-hosted/stage2.zig
+++ b/src-self-hosted/stage2.zig
@@ -1163,6 +1163,7 @@ fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8)
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);
From 4591236ae1de25e55a7d134d5cc0dcc3e1ad6a6e Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 28 Feb 2020 18:31:46 -0500
Subject: [PATCH 36/62] CrossTarget.cpu_model: communicate intent precisely
---
lib/std/zig/cross_target.zig | 75 ++++++++++++++++++++++--------------
lib/std/zig/system.zig | 31 ++++++++++-----
src-self-hosted/stage2.zig | 2 +-
3 files changed, 69 insertions(+), 39 deletions(-)
diff --git a/lib/std/zig/cross_target.zig b/lib/std/zig/cross_target.zig
index a2d265707b..16c0a64f6b 100644
--- a/lib/std/zig/cross_target.zig
+++ b/lib/std/zig/cross_target.zig
@@ -7,11 +7,10 @@ const mem = std.mem;
/// 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. If this is `null` then `cpu_model` must be `null`.
+ /// `null` means native.
cpu_arch: ?Target.Cpu.Arch = null,
- /// `null` means native. If this is non-null, `cpu_arch` must be specified.
- cpu_model: ?*const Target.Cpu.Model = 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,
@@ -41,6 +40,20 @@ pub const CrossTarget = struct {
/// 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,
@@ -54,7 +67,7 @@ pub const CrossTarget = struct {
pub fn fromTarget(target: Target) CrossTarget {
var result: CrossTarget = .{
.cpu_arch = target.cpu.arch,
- .cpu_model = target.cpu.model,
+ .cpu_model = .{ .explicit = target.cpu.model },
.os_tag = target.os.tag,
.os_version_min = undefined,
.os_version_max = undefined,
@@ -266,11 +279,11 @@ pub const CrossTarget = struct {
const add_set = &result.cpu_features_add;
const sub_set = &result.cpu_features_sub;
if (mem.eql(u8, cpu_name, "native")) {
- result.cpu_model = null;
+ result.cpu_model = .native;
} else if (mem.eql(u8, cpu_name, "baseline")) {
- result.cpu_model = Target.Cpu.Model.baseline(arch);
+ result.cpu_model = .baseline;
} else {
- result.cpu_model = try arch.parseCpuModel(cpu_name);
+ result.cpu_model = .{ .explicit = try arch.parseCpuModel(cpu_name) };
}
while (index < cpu_features.len) {
@@ -300,10 +313,6 @@ pub const CrossTarget = struct {
return error.UnknownCpuFeature;
}
}
- } else if (arch_is_native) {
- result.cpu_model = null;
- } else {
- result.cpu_model = Target.Cpu.Model.baseline(arch);
}
return result;
@@ -311,24 +320,33 @@ pub const CrossTarget = struct {
/// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
pub fn getCpu(self: CrossTarget) Target.Cpu {
- if (self.cpu_arch) |arch| {
- if (self.cpu_model) |model| {
- var adjusted_model = model.toCpu(arch);
- self.updateCpuFeatures(&adjusted_model.features);
- return adjusted_model;
- } else {
- var adjusted_baseline = Target.Cpu.baseline(arch);
+ 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;
- }
- } else {
- assert(self.cpu_model == null);
- assert(self.cpu_features_sub.isEmpty());
- assert(self.cpu_features_add.isEmpty());
- // 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;
+ },
+ .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;
+ },
}
}
@@ -461,7 +479,8 @@ pub const CrossTarget = struct {
}
pub fn isNative(self: CrossTarget) bool {
- return self.cpu_arch == null and self.cpu_model == null and
+ 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;
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index b712c7c062..5ff17bae23 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -191,18 +191,18 @@ pub const NativeTargetInfo = struct {
/// deinitialization method.
/// TODO Remove the Allocator requirement from this function.
pub fn detect(allocator: *Allocator, cross_target: CrossTarget) DetectError!NativeTargetInfo {
- const cpu = blk: {
- const arch = cross_target.getCpuArch();
- if (cross_target.cpu_model) |model| {
- var adjusted_model = model.toCpu(arch);
+ 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;
- } else {
- // TODO Detect native CPU model & features. Until that is implemented we use baseline.
- var adjusted_baseline = Target.Cpu.baseline(arch);
- cross_target.updateCpuFeatures(&adjusted_baseline.features);
- break :blk adjusted_baseline;
- }
+ },
};
var os = Target.Os.defaultVersionRange(cross_target.getOsTag());
@@ -758,4 +758,15 @@ pub const NativeTargetInfo = struct {
}
}
}
+
+ 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;
+ }
};
diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig
index 696d7ea760..a8aa10d91e 100644
--- a/src-self-hosted/stage2.zig
+++ b/src-self-hosted/stage2.zig
@@ -1154,7 +1154,7 @@ fn enumInt(comptime Enum: type, int: c_int) Enum {
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 == null) {
+ 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");
From 7e3bb00a0e919bdb2a778a7efb648dfc6afa8318 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 28 Feb 2020 18:48:19 -0500
Subject: [PATCH 37/62] don't choose native ld path when os is non native
---
lib/std/zig/system.zig | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index 5ff17bae23..aa8def32a9 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -274,7 +274,8 @@ pub const NativeTargetInfo = struct {
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());
- if (!native_target_has_ld or have_all_info) {
+ 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
From 4bc893c346aa45972ae884188388269b66efc3b9 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 28 Feb 2020 19:05:14 -0500
Subject: [PATCH 38/62] update test to newer API
---
lib/std/zig/cross_target.zig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/std/zig/cross_target.zig b/lib/std/zig/cross_target.zig
index 16c0a64f6b..66b7344840 100644
--- a/lib/std/zig/cross_target.zig
+++ b/lib/std/zig/cross_target.zig
@@ -754,7 +754,7 @@ test "CrossTarget.parse" {
});
std.testing.expect(cross_target.cpu_arch.? == .aarch64);
- std.testing.expect(cross_target.cpu_model == null);
+ std.testing.expect(cross_target.cpu_model == .native);
}
{
const cross_target = try CrossTarget.parse(.{ .arch_os_abi = "native" });
From e683eee415bc4362f9c0e095ceecebe577c47d06 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 28 Feb 2020 19:18:27 -0500
Subject: [PATCH 39/62] fix CrossTarget.isNative, setGnuLibCVersion, zigTriple
---
lib/std/zig/cross_target.zig | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/lib/std/zig/cross_target.zig b/lib/std/zig/cross_target.zig
index 66b7344840..08a8d21fad 100644
--- a/lib/std/zig/cross_target.zig
+++ b/lib/std/zig/cross_target.zig
@@ -483,7 +483,7 @@ pub const CrossTarget = struct {
(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;
+ 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 {
@@ -514,13 +514,10 @@ pub const CrossTarget = struct {
}
}
- if (self.abi) |abi| {
+ if (self.glibc_version) |v| {
+ try result.print("-{}.{}", .{ @tagName(self.getAbi()), v });
+ } else if (self.abi) |abi| {
try result.print("-{}", .{@tagName(abi)});
- if (self.glibc_version) |v| {
- try result.print(".{}", .{v});
- }
- } else {
- assert(self.glibc_version == null);
}
return result.toOwnedSlice();
@@ -643,7 +640,7 @@ pub const CrossTarget = struct {
return Target.isGnuLibC_os_tag_abi(self.getOsTag(), self.getAbi());
}
- pub fn setGnuLibCVersion(self: CrossTarget, major: u32, minor: u32, patch: u32) void {
+ 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 };
}
@@ -747,6 +744,14 @@ pub const CrossTarget = struct {
};
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",
From 1aef0bef754ddf1943e22740ef045fab7769cde1 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 28 Feb 2020 19:24:52 -0500
Subject: [PATCH 40/62] std.Target.Os.WindowsVersion: non-exhaustive enum
---
lib/std/target.zig | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/std/target.zig b/lib/std/target.zig
index 3054c60467..5807ba65ef 100644
--- a/lib/std/target.zig
+++ b/lib/std/target.zig
@@ -91,6 +91,7 @@ pub const Target = struct {
win10_rs4 = 0x0A000005,
win10_rs5 = 0x0A000006,
win10_19h1 = 0x0A000007,
+ _,
pub const Range = struct {
min: WindowsVersion,
From 3cba603eae1a1c8b0338f5584041c73d55682c0a Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 29 Feb 2020 01:05:11 -0500
Subject: [PATCH 41/62] fix crash when building docgen
---
src/analyze.cpp | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 90037a1191..1a9172c030 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -6734,8 +6734,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:
@@ -6746,6 +6744,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();
From 1b41f2d77ea14de27b0655a35a727d664cfc4ca4 Mon Sep 17 00:00:00 2001
From: Alexandros Naskos
Date: Sat, 29 Feb 2020 08:36:42 +0200
Subject: [PATCH 42/62] C pointer slices are no longer allowzero (#4462)
* Slices from C pointers are no longer allowzero but instead insert a runtime assertion.
* Added a test, fixed code for cases with non-allowzero C pointers
* Create new type when flipping allow_zero, sometimes we get a cached value back from adjust_ptr_len.
* Added comments, changed panic message
* Added runtime safety test.
---
src/codegen.cpp | 2 +-
src/ir.cpp | 35 +++++++++++++++++++++++++++++++---
test/runtime_safety.zig | 13 +++++++++++++
test/stage1/behavior/slice.zig | 11 +++++++++++
4 files changed, 57 insertions(+), 4 deletions(-)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index ee3e05a801..69220382cd 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -973,7 +973,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:
diff --git a/src/ir.cpp b/src/ir.cpp
index 895cfa334c..72e247b75a 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -20412,6 +20412,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;
@@ -25966,6 +25977,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 &&
@@ -25993,6 +26006,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);
@@ -26264,7 +26285,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;
@@ -26277,8 +26297,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) {
diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig
index e4ea7f52db..e183c6979f 100644
--- a/test/runtime_safety.zig
+++ b/test/runtime_safety.zig
@@ -745,4 +745,17 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\ (await p) catch unreachable;
\\}
);
+
+ // Slicing a C pointer returns a non-allowzero slice, thus we need to emit
+ // a safety check to ensure the pointer is not null.
+ cases.addRuntimeSafety("slicing null C pointer",
+ \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
+ \\ @import("std").os.exit(126);
+ \\}
+ \\
+ \\pub fn main() void {
+ \\ var ptr: [*c]const u32 = null;
+ \\ var slice = ptr[0..3];
+ \\}
+ );
}
diff --git a/test/stage1/behavior/slice.zig b/test/stage1/behavior/slice.zig
index c0fa723cfb..9dd57f474e 100644
--- a/test/stage1/behavior/slice.zig
+++ b/test/stage1/behavior/slice.zig
@@ -43,6 +43,17 @@ test "C pointer" {
expectEqualSlices(u8, "kjdhfkjdhf", slice);
}
+test "C pointer slice access" {
+ var buf: [10]u32 = [1]u32{42} ** 10;
+ const c_ptr = @ptrCast([*c]const u32, &buf);
+
+ comptime expectEqual([]const u32, @TypeOf(c_ptr[0..1]));
+
+ for (c_ptr[0..5]) |*cl| {
+ expectEqual(@as(u32, 42), cl.*);
+ }
+}
+
fn sliceSum(comptime q: []const u8) i32 {
comptime var result = 0;
inline for (q) |item| {
From 7e6b68a534f840d2d08770a5a77896707271e8ea Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 29 Feb 2020 02:08:26 -0500
Subject: [PATCH 43/62] std.Target.standardDynamicLinkerPath: delete bad doc
comment
---
lib/std/target.zig | 2 --
1 file changed, 2 deletions(-)
diff --git a/lib/std/target.zig b/lib/std/target.zig
index 5807ba65ef..0082510505 100644
--- a/lib/std/target.zig
+++ b/lib/std/target.zig
@@ -1133,8 +1133,6 @@ pub const Target = struct {
}
};
- /// The result will be a byte index *pointing at the final byte*. In other words, length minus one.
- /// A return value of `null` means the concept of a dynamic linker is not meaningful for that target.
pub fn standardDynamicLinkerPath(self: Target) DynamicLinker {
var result: DynamicLinker = .{};
const S = struct {
From f072b0c056768648eb56230036dc8c973116d066 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sat, 29 Feb 2020 12:00:58 +0100
Subject: [PATCH 44/62] target: Implement OS version detection for Windows
Closes #4581
---
lib/std/os/windows/bits.zig | 13 ++++++++++++
lib/std/os/windows/ntdll.zig | 10 ++++++++-
lib/std/zig/system.zig | 40 +++++++++++++++++++++++++++++++++++-
3 files changed, 61 insertions(+), 2 deletions(-)
diff --git a/lib/std/os/windows/bits.zig b/lib/std/os/windows/bits.zig
index 4e153d40ed..761b508373 100644
--- a/lib/std/os/windows/bits.zig
+++ b/lib/std/os/windows/bits.zig
@@ -1321,3 +1321,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;
diff --git a/lib/std/os/windows/ntdll.zig b/lib/std/os/windows/ntdll.zig
index e98a2e6a87..49e60803bc 100644
--- a/lib/std/os/windows/ntdll.zig
+++ b/lib/std/os/windows/ntdll.zig
@@ -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,
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index aa8def32a9..333a5c3950 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -181,6 +181,7 @@ pub const NativeTargetInfo = struct {
ProcessFdQuotaExceeded,
SystemFdQuotaExceeded,
DeviceBusy,
+ Unexpected,
};
/// Given a `CrossTarget`, which specifies in detail which parts of the target should be detected
@@ -221,7 +222,44 @@ pub const NativeTargetInfo = struct {
}
},
.windows => {
- // TODO Detect native operating system version.
+ var version_info: std.os.windows.RTL_OSVERSIONINFOW = undefined;
+ version_info.dwOSVersionInfoSize = @sizeOf(@TypeOf(version_info));
+
+ const rc = std.os.windows.ntdll.RtlGetVersion(&version_info);
+ switch (rc) {
+ .SUCCESS => {},
+ else => return std.os.windows.unexpectedStatus(rc),
+ }
+
+ // 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 >= 0xA000) subver: {
+ // There's no other way to obtain this info beside
+ // checking the build number against a known set of
+ // values
+ for ([_]u32{
+ 10240, 10586, 14393, 15063, 16299, 17134, 17763,
+ 18362, 18363,
+ }) |build, i| {
+ if (version_info.dwBuildNumber < build)
+ break :subver @truncate(u8, i);
+ }
+ // Unknown subversion, the OS is too new...
+ break :subver 0;
+ } 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 => {
// TODO Detect native operating system version.
From 513076ee9ced78999eae283bde23c64d26330cf7 Mon Sep 17 00:00:00 2001
From: daurnimator
Date: Sat, 29 Feb 2020 23:56:17 +1100
Subject: [PATCH 45/62] Fill out PEB definition
---
lib/std/os/windows/bits.zig | 174 +++++++++++++++++++++++++++++++++---
1 file changed, 160 insertions(+), 14 deletions(-)
diff --git a/lib/std/os/windows/bits.zig b/lib/std/os/windows/bits.zig
index 4e153d40ed..89e02fc7f1 100644
--- a/lib/std/os/windows/bits.zig
+++ b/lib/std/os/windows/bits.zig
@@ -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,28 +1147,172 @@ 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,
};
+// TODO: 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,
From 58222204353c052a62f3723f879dc16f2d608f8b Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sat, 29 Feb 2020 14:19:13 +0100
Subject: [PATCH 46/62] Address review comments
---
lib/std/zig/system.zig | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index 333a5c3950..b04fb12885 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -181,7 +181,6 @@ pub const NativeTargetInfo = struct {
ProcessFdQuotaExceeded,
SystemFdQuotaExceeded,
DeviceBusy,
- Unexpected,
};
/// Given a `CrossTarget`, which specifies in detail which parts of the target should be detected
@@ -225,10 +224,9 @@ pub const NativeTargetInfo = struct {
var version_info: std.os.windows.RTL_OSVERSIONINFOW = undefined;
version_info.dwOSVersionInfoSize = @sizeOf(@TypeOf(version_info));
- const rc = std.os.windows.ntdll.RtlGetVersion(&version_info);
- switch (rc) {
+ switch (std.os.windows.ntdll.RtlGetVersion(&version_info)) {
.SUCCESS => {},
- else => return std.os.windows.unexpectedStatus(rc),
+ else => unreachable,
}
// Starting from the system infos build a NTDDI-like version
@@ -245,15 +243,16 @@ pub const NativeTargetInfo = struct {
// There's no other way to obtain this info beside
// checking the build number against a known set of
// values
- for ([_]u32{
+ const known_build_numbers = [_]u32{
10240, 10586, 14393, 15063, 16299, 17134, 17763,
18362, 18363,
- }) |build, i| {
+ };
+ for (known_build_numbers) |build, i| {
if (version_info.dwBuildNumber < build)
break :subver @truncate(u8, i);
}
// Unknown subversion, the OS is too new...
- break :subver 0;
+ break :subver @truncate(u8, known_build_numbers.len);
} else 0;
const version: u32 = @as(u32, os_ver) << 16 | @as(u32, sp_ver) << 8 | sub_ver;
From d0c22619f59e41cb07d26d878ed1a9ec87e550e1 Mon Sep 17 00:00:00 2001
From: daurnimator
Date: Sun, 1 Mar 2020 02:10:29 +1100
Subject: [PATCH 47/62] Complete windows PEB_LDR_DATA definition
---
lib/std/os/windows/bits.zig | 32 +++++++++++++++++++++++++++++---
1 file changed, 29 insertions(+), 3 deletions(-)
diff --git a/lib/std/os/windows/bits.zig b/lib/std/os/windows/bits.zig
index 89e02fc7f1..923644b646 100644
--- a/lib/std/os/windows/bits.zig
+++ b/lib/std/os/windows/bits.zig
@@ -1312,11 +1312,37 @@ pub const PEB = extern struct {
CloudFileFlags: ULONG,
};
-// TODO: https://www.geoffchappell.com/studies/windows/win32/ntdll/structs/peb_ldr_data.htm
+/// 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 {
From 3c7f030a60b038045334788837f40bee0226109c Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 29 Feb 2020 12:27:13 -0500
Subject: [PATCH 48/62] add CrossTarget.getObjectFormat
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
closes #4588
thanks Michaël Larouche for the suggested fix
---
lib/std/target.zig | 12 ++++++++----
lib/std/zig/cross_target.zig | 4 ++++
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/lib/std/target.zig b/lib/std/target.zig
index 0082510505..c810c01ec3 100644
--- a/lib/std/target.zig
+++ b/lib/std/target.zig
@@ -1014,18 +1014,22 @@ pub const Target = struct {
return libPrefix_cpu_arch_abi(self.cpu.arch, self.abi);
}
- pub fn getObjectFormat(self: Target) ObjectFormat {
- if (self.os.tag == .windows or self.os.tag == .uefi) {
+ pub fn getObjectFormatSimple(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat {
+ if (os_tag == .windows or os_tag == .uefi) {
return .coff;
- } else if (self.isDarwin()) {
+ } else if (os_tag.isDarwin()) {
return .macho;
}
- if (self.cpu.arch.isWasm()) {
+ if (cpu_arch.isWasm()) {
return .wasm;
}
return .elf;
}
+ pub fn getObjectFormat(self: Target) ObjectFormat {
+ return getObjectFormatSimple(self.os.tag, self.cpu.arch);
+ }
+
pub fn isMinGW(self: Target) bool {
return self.os.tag == .windows and self.isGnu();
}
diff --git a/lib/std/zig/cross_target.zig b/lib/std/zig/cross_target.zig
index 08a8d21fad..38ce6549f3 100644
--- a/lib/std/zig/cross_target.zig
+++ b/lib/std/zig/cross_target.zig
@@ -645,6 +645,10 @@ pub const CrossTarget = struct {
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);
From 278f0f8fa97610589dfb28c8fffedca7298e6715 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sat, 29 Feb 2020 18:31:03 +0100
Subject: [PATCH 49/62] Change how the build-id is checked
Address review comment by @rocksnest
---
lib/std/zig/system.zig | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index b04fb12885..e76d2eaca1 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -239,7 +239,7 @@ pub const NativeTargetInfo = struct {
@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 >= 0xA000) subver: {
+ 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
@@ -247,12 +247,12 @@ pub const NativeTargetInfo = struct {
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)
- break :subver @truncate(u8, i);
+ if (version_info.dwBuildNumber >= build)
+ last_idx = i;
}
- // Unknown subversion, the OS is too new...
- break :subver @truncate(u8, known_build_numbers.len);
+ break :subver @truncate(u8, last_idx);
} else 0;
const version: u32 = @as(u32, os_ver) << 16 | @as(u32, sp_ver) << 8 | sub_ver;
From 84549b39550014ca85d34c93381cadbd93080a0e Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sat, 29 Feb 2020 21:46:07 +0100
Subject: [PATCH 50/62] target: Implement OS version detection for OSX
Closes #4583
---
lib/std/os.zig | 3 +++
lib/std/zig/system.zig | 26 +++++++++++++++++++++++++-
2 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 49e88bf9c7..24d78bec9a 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -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),
}
}
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index aa8def32a9..234c1a6550 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -224,7 +224,31 @@ pub const NativeTargetInfo = struct {
// TODO Detect native operating system version.
},
.macosx => {
- // TODO Detect native operating system version.
+ var product_version: [32]u8 = undefined;
+ var size: usize = @sizeOf(@TypeOf(product_version));
+
+ // 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[0],
+ &size,
+ null,
+ 0,
+ ) catch |err| switch (err) {
+ error.UnknownName => unreachable,
+ else => unreachable,
+ };
+
+ if (std.builtin.Version.parse(product_version[0..size])) |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.
From 3b29a72b3b59803307e9040a6832e579901211f3 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sat, 29 Feb 2020 23:08:57 +0100
Subject: [PATCH 51/62] Use .len instead of @sizeOf
---
lib/std/zig/system.zig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index 234c1a6550..7e23410fa8 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -225,7 +225,7 @@ pub const NativeTargetInfo = struct {
},
.macosx => {
var product_version: [32]u8 = undefined;
- var size: usize = @sizeOf(@TypeOf(product_version));
+ var size: usize = product_version.len;
// The osproductversion sysctl was introduced first with
// High Sierra, thankfully that's also the baseline that Zig
From 845af5c55208753dc355fad734a8c4893338f8f6 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sat, 29 Feb 2020 23:11:36 +0100
Subject: [PATCH 52/62] Handle one more error
---
lib/std/thread.zig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/std/thread.zig b/lib/std/thread.zig
index 55db9d1733..de9d580af7 100644
--- a/lib/std/thread.zig
+++ b/lib/std/thread.zig
@@ -382,7 +382,7 @@ pub const Thread = struct {
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);
From 48cef8d5be24c40b4c845f6b07c78abd6c3d1b0d Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 29 Feb 2020 21:31:03 -0500
Subject: [PATCH 53/62] refactor std.zig.system.NativeTargetInfo functions
to make them a bit easier to test.
---
lib/std/zig/system.zig | 65 ++++++++++++++++++++++--------------------
1 file changed, 34 insertions(+), 31 deletions(-)
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index 7e23410fa8..37834b4412 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -399,17 +399,38 @@ pub const NativeTargetInfo = struct {
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 abiAndDynamicLinkerFromUsrBinEnv(cpu, os, ld_info_list, cross_target) catch |err| switch (err) {
+ 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,
- error.DeviceBusy,
=> |e| return e,
error.UnableToReadElfFile,
@@ -418,7 +439,6 @@ pub const NativeTargetInfo = struct {
error.InvalidElfEndian,
error.InvalidElfFile,
error.InvalidElfMagic,
- error.UsrBinEnvNotAvailable,
error.Unexpected,
error.UnexpectedEndOfFile,
error.NameTooLong,
@@ -461,32 +481,15 @@ pub const NativeTargetInfo = struct {
};
}
- fn abiAndDynamicLinkerFromUsrBinEnv(
+ pub fn abiAndDynamicLinkerFromFile(
+ file: fs.File,
cpu: Target.Cpu,
os: Target.Os,
ld_info_list: []const LdInfo,
cross_target: CrossTarget,
) !NativeTargetInfo {
- 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 => return error.UsrBinEnvNotAvailable,
- error.NotDir => return error.UsrBinEnvNotAvailable,
- error.AccessDenied => return error.UsrBinEnvNotAvailable,
- error.NoDevice => return error.UsrBinEnvNotAvailable,
- error.FileNotFound => return error.UsrBinEnvNotAvailable,
- error.FileTooBig => return error.UsrBinEnvNotAvailable,
-
- else => |e| return e,
- };
var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined;
- _ = try preadFull(env_file, &hdr_buf, 0, hdr_buf.len);
+ _ = 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;
@@ -526,7 +529,7 @@ pub const NativeTargetInfo = struct {
// 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(env_file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize);
+ 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;
@@ -541,7 +544,7 @@ pub const NativeTargetInfo = struct {
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(env_file, result.dynamic_linker.buffer[0..p_filesz], p_offset, p_filesz);
+ _ = 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".
@@ -573,7 +576,7 @@ pub const NativeTargetInfo = struct {
// 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(
- env_file,
+ file,
dyn_buf[0 .. dyn_buf.len - dyn_reserve],
dyn_off,
dyn_size,
@@ -617,14 +620,14 @@ pub const NativeTargetInfo = struct {
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(env_file, &sh_buf, str_section_off, shentsize);
+ _ = 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(env_file, &strtab_buf, shstrtab_off, shstrtab_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);
@@ -634,7 +637,7 @@ pub const NativeTargetInfo = struct {
// 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(
- env_file,
+ file,
sh_buf[0 .. sh_buf.len - sh_reserve],
shoff,
shentsize,
@@ -667,7 +670,7 @@ pub const NativeTargetInfo = struct {
if (dynstr) |ds| {
const strtab_len = std.math.min(ds.size, strtab_buf.len);
- const strtab_read_len = try preadFull(env_file, &strtab_buf, ds.offset, shstrtab_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));
@@ -763,7 +766,7 @@ pub const NativeTargetInfo = struct {
};
}
- const LdInfo = struct {
+ pub const LdInfo = struct {
ld: DynamicLinker,
abi: Target.Abi,
};
From 6fcf6716be3021d99d4972e8ca9b2139e1f8f40b Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 29 Feb 2020 22:13:09 -0500
Subject: [PATCH 54/62] std.Thread.cpuCount on Windows uses the PEB
rather than calling GetSystemInfo from kernel32.dll. Also remove
OutOfMemory from the error set.
---
lib/std/thread.zig | 31 ++++++++++++++-----------------
1 file changed, 14 insertions(+), 17 deletions(-)
diff --git a/lib/std/thread.zig b/lib/std/thread.zig
index de9d580af7..b2f8a44a47 100644
--- a/lib/std/thread.zig
+++ b/lib/std/thread.zig
@@ -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.tag != .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.tag) {
+ 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.tag) {
+ 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.tag) {
+ 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.tag) {
+ 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.tag) {
+ } 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.tag == .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.tag == .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,21 +362,18 @@ pub const Thread = struct {
}
pub const CpuCountError = error{
- OutOfMemory,
PermissionDenied,
SystemResources,
Unexpected,
};
pub fn cpuCount() CpuCountError!usize {
- if (builtin.os.tag == .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.tag == .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);
From 22468121849e902a0ac2435af21fb9c773c7bcc4 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 29 Feb 2020 22:20:44 -0500
Subject: [PATCH 55/62] use an explicit error set to fix a compilation error
this function has conditionally compiled out code in it about looking
for native glibc.
---
lib/std/zig/system.zig | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index 37834b4412..5767291de7 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -481,13 +481,30 @@ pub const NativeTargetInfo = struct {
};
}
+ 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,
- ) !NativeTargetInfo {
+ ) 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);
From f082e253b56b98a806e5ec047c5eb197b2c8ab88 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 1 Mar 2020 01:17:50 -0500
Subject: [PATCH 56/62] fix native OS version detection on macOS
closes #4583
---
lib/std/zig/system.zig | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index 5767291de7..df50b4a4c2 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -232,7 +232,7 @@ pub const NativeTargetInfo = struct {
// supports
std.os.sysctlbynameC(
"kern.osproductversion",
- &product_version[0],
+ &product_version,
&size,
null,
0,
@@ -241,7 +241,8 @@ pub const NativeTargetInfo = struct {
else => unreachable,
};
- if (std.builtin.Version.parse(product_version[0..size])) |ver| {
+ 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) {
From b99c6d56da3d2db995c268fb07f48548ea6d1148 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 1 Mar 2020 03:27:09 -0500
Subject: [PATCH 57/62] stage1: fix compilation on 32-bit arm
---
src/os.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/os.cpp b/src/os.cpp
index 8e0bcc433b..f65a578e17 100644
--- a/src/os.cpp
+++ b/src/os.cpp
@@ -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) {
From 0b0de22fd1b0391f0cf1c7d821afc6522041c699 Mon Sep 17 00:00:00 2001
From: daurnimator
Date: Fri, 27 Dec 2019 14:31:20 +1100
Subject: [PATCH 58/62] std: format contents of sentinel terminated many
pointers
std: add std.meta.Sentinel to get sentinel of a type
---
lib/std/cstr.zig | 2 +-
lib/std/fmt.zig | 8 ++++++--
lib/std/mem.zig | 23 ++++++++++++++++++-----
lib/std/meta.zig | 26 ++++++++++++++++++++++++++
src-self-hosted/main.zig | 14 +++++++-------
test/stage1/behavior/misc.zig | 2 +-
6 files changed, 59 insertions(+), 16 deletions(-)
diff --git a/lib/std/cstr.zig b/lib/std/cstr.zig
index 4057d4b62b..6b2407cb7d 100644
--- a/lib/std/cstr.zig
+++ b/lib/std/cstr.zig
@@ -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(u8, "123456789".*) == 9);
}
/// Returns a mutable, null-terminated slice with the same length as `slice`.
diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig
index d093101646..97f2133d67 100644
--- a/lib/std/fmt.zig
+++ b/lib/std/fmt.zig
@@ -441,10 +441,14 @@ pub fn formatType(
else => return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
},
.Many, .C => {
+ if (ptr_info.sentinel) |sentinel| {
+ const slice = mem.pointerToSlice([:sentinel]const ptr_info.child, value);
+ return formatType(slice, 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);
+ const slice = mem.pointerToSlice([:0]const u8, @as([*:0]const u8, value));
+ return formatText(slice, fmt, options, context, Errors, output);
}
}
return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
diff --git a/lib/std/mem.zig b/lib/std/mem.zig
index a4b48bbc1c..e6ef7d6752 100644
--- a/lib/std/mem.zig
+++ b/lib/std/mem.zig
@@ -470,18 +470,31 @@ 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 {
+pub fn len(comptime T: type, ptr: var) usize {
+ const sentinel: T = comptime meta.Sentinel(@TypeOf(ptr));
var count: usize = 0;
- while (ptr[count] != 0) : (count += 1) {}
+ while (ptr[count] != sentinel) : (count += 1) {}
return count;
}
-pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T {
- return ptr[0..len(T, ptr) :0];
+/// Given a sentintel-terminated pointer-to-many, find the sentintel and return a slice.
+pub fn pointerToSlice(comptime T: type, ptr: blk: {
+ var info = @typeInfo(T).Pointer;
+ info.size = .Many;
+ break :blk @Type(std.builtin.TypeInfo{ .Pointer = info });
+}) T {
+ const sentinel = comptime meta.Sentinel(T);
+ return ptr[0..len(meta.Child(T), ptr) :sentinel];
}
+/// Deprecated; use pointerToSlice instead
+pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T {
+ return pointerToSlice([:0]const T, ptr);
+}
+
+/// Deprecated; use pointerToSlice instead
pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T {
- return ptr[0..len(T, ptr) :0];
+ return pointerToSlice([:0]T, ptr);
}
/// Returns true if all elements in a slice are equal to the scalar value provided
diff --git a/lib/std/meta.zig b/lib/std/meta.zig
index 58fd6b9da7..65809abb5c 100644
--- a/lib/std/meta.zig
+++ b/lib/std/meta.zig
@@ -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,
diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig
index 264a896f46..4446a974d4 100644
--- a/src-self-hosted/main.zig
+++ b/src-self-hosted/main.zig
@@ -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,
});
}
diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig
index 681f5be500..e2513c3f4a 100644
--- a/test/stage1/behavior/misc.zig
+++ b/test/stage1/behavior/misc.zig
@@ -335,7 +335,7 @@ test "string concatenation" {
comptime expect(@TypeOf(a) == *const [12:0]u8);
comptime expect(@TypeOf(b) == *const [12:0]u8);
- const len = mem.len(u8, b);
+ const len = b.len;
const len_with_null = len + 1;
{
var i: u32 = 0;
From 4505857e30233d87f9ece403458c0988e8c68493 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 1 Mar 2020 13:07:31 -0500
Subject: [PATCH 59/62] revert changes outside std.fmt
---
lib/std/cstr.zig | 2 +-
lib/std/mem.zig | 21 ++++-----------------
test/stage1/behavior/misc.zig | 2 +-
3 files changed, 6 insertions(+), 19 deletions(-)
diff --git a/lib/std/cstr.zig b/lib/std/cstr.zig
index 6b2407cb7d..4057d4b62b 100644
--- a/lib/std/cstr.zig
+++ b/lib/std/cstr.zig
@@ -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(u8, "123456789") == 9);
}
/// Returns a mutable, null-terminated slice with the same length as `slice`.
diff --git a/lib/std/mem.zig b/lib/std/mem.zig
index e6ef7d6752..a4b48bbc1c 100644
--- a/lib/std/mem.zig
+++ b/lib/std/mem.zig
@@ -470,31 +470,18 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
return true;
}
-pub fn len(comptime T: type, ptr: var) usize {
- const sentinel: T = comptime meta.Sentinel(@TypeOf(ptr));
+pub fn len(comptime T: type, ptr: [*:0]const T) usize {
var count: usize = 0;
- while (ptr[count] != sentinel) : (count += 1) {}
+ while (ptr[count] != 0) : (count += 1) {}
return count;
}
-/// Given a sentintel-terminated pointer-to-many, find the sentintel and return a slice.
-pub fn pointerToSlice(comptime T: type, ptr: blk: {
- var info = @typeInfo(T).Pointer;
- info.size = .Many;
- break :blk @Type(std.builtin.TypeInfo{ .Pointer = info });
-}) T {
- const sentinel = comptime meta.Sentinel(T);
- return ptr[0..len(meta.Child(T), ptr) :sentinel];
-}
-
-/// Deprecated; use pointerToSlice instead
pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T {
- return pointerToSlice([:0]const T, ptr);
+ return ptr[0..len(T, ptr) :0];
}
-/// Deprecated; use pointerToSlice instead
pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T {
- return pointerToSlice([:0]T, ptr);
+ return ptr[0..len(T, ptr) :0];
}
/// Returns true if all elements in a slice are equal to the scalar value provided
diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig
index e2513c3f4a..681f5be500 100644
--- a/test/stage1/behavior/misc.zig
+++ b/test/stage1/behavior/misc.zig
@@ -335,7 +335,7 @@ test "string concatenation" {
comptime expect(@TypeOf(a) == *const [12:0]u8);
comptime expect(@TypeOf(b) == *const [12:0]u8);
- const len = b.len;
+ const len = mem.len(u8, b);
const len_with_null = len + 1;
{
var i: u32 = 0;
From 5b26128bacddf594dfe45958a236bfa2459f878b Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 1 Mar 2020 13:07:55 -0500
Subject: [PATCH 60/62] add new functions to std.mem and deprecate others
add std.mem.Span
add std.mem.span
add std.mem.length
add std.mem.indexOfSentinel
deprecate std.mem.len
deprecate std.mem.toSlice
deprecate std.mem.toSliceConst
---
lib/std/builtin.zig | 2 +
lib/std/mem.zig | 118 +++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 118 insertions(+), 2 deletions(-)
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index de37fda903..a4f0ef269f 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -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`.
diff --git a/lib/std/mem.zig b/lib/std/mem.zig
index a4b48bbc1c..775e999e0b 100644
--- a/lib/std/mem.zig
+++ b/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,20 +482,122 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
return true;
}
+/// Deprecated. Use `length` or `indexOfSentinel`.
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];
}
+/// Deprecated. Use `span`.
pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T {
return ptr[0..len(T, 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.
+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;
+ },
+ .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 = length(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 length(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 "length" {
+ testing.expect(length("aoeu") == 4);
+
+ {
+ var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
+ testing.expect(length(&array) == 5);
+ testing.expect(length(array[0..3]) == 3);
+ array[2] = 0;
+ const ptr = array[0..2 :0].ptr;
+ testing.expect(length(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
pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool {
for (slice) |item| {
From ef3d761da545a3a72928ed0e0ba3b749a4cb74d8 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 1 Mar 2020 13:21:29 -0500
Subject: [PATCH 61/62] breaking: std.mem.len no longer takes a type argument
also update fmt code to use std.mem.span.
---
lib/std/cstr.zig | 2 +-
lib/std/fmt.zig | 6 ++----
lib/std/mem.zig | 38 ++++++++++++++++-----------------
lib/std/net.zig | 2 +-
lib/std/os.zig | 2 +-
lib/std/special/c.zig | 2 +-
src-self-hosted/translate_c.zig | 2 +-
test/stage1/behavior/misc.zig | 2 +-
8 files changed, 27 insertions(+), 29 deletions(-)
diff --git a/lib/std/cstr.zig b/lib/std/cstr.zig
index 4057d4b62b..9cb16b0ed3 100644
--- a/lib/std/cstr.zig
+++ b/lib/std/cstr.zig
@@ -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`.
diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig
index 97f2133d67..3729b7dc87 100644
--- a/lib/std/fmt.zig
+++ b/lib/std/fmt.zig
@@ -442,13 +442,11 @@ pub fn formatType(
},
.Many, .C => {
if (ptr_info.sentinel) |sentinel| {
- const slice = mem.pointerToSlice([:sentinel]const ptr_info.child, value);
- return formatType(slice, fmt, options, context, Errors, output, max_depth);
+ 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 slice = mem.pointerToSlice([:0]const u8, @as([*:0]const u8, value));
- return formatText(slice, 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) });
diff --git a/lib/std/mem.zig b/lib/std/mem.zig
index 775e999e0b..a6c4d0057e 100644
--- a/lib/std/mem.zig
+++ b/lib/std/mem.zig
@@ -482,27 +482,21 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
return true;
}
-/// Deprecated. Use `length` or `indexOfSentinel`.
-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.
+/// 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) {
@@ -515,6 +509,7 @@ pub fn Span(comptime T: type) type {
},
.C => {
ptr_info.sentinel = 0;
+ ptr_info.is_allowzero = false;
},
.Many, .Slice => {},
}
@@ -541,7 +536,7 @@ test "Span" {
/// the constness of the input type.
pub fn span(ptr: var) Span(@TypeOf(ptr)) {
const Result = Span(@TypeOf(ptr));
- const l = length(ptr);
+ const l = len(ptr);
if (@typeInfo(Result).Pointer.sentinel) |s| {
return ptr[0..l :s];
} else {
@@ -558,7 +553,7 @@ test "span" {
/// Takes a pointer to an array, an array, a sentinel-terminated pointer,
/// or a slice, and returns the length.
-pub fn length(ptr: var) usize {
+pub fn len(ptr: var) usize {
return switch (@typeInfo(@TypeOf(ptr))) {
.Array => |info| info.len,
.Pointer => |info| switch (info.size) {
@@ -577,16 +572,16 @@ pub fn length(ptr: var) usize {
};
}
-test "length" {
- testing.expect(length("aoeu") == 4);
+test "len" {
+ testing.expect(len("aoeu") == 4);
{
var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
- testing.expect(length(&array) == 5);
- testing.expect(length(array[0..3]) == 3);
+ testing.expect(len(&array) == 5);
+ testing.expect(len(array[0..3]) == 3);
array[2] = 0;
const ptr = array[0..2 :0].ptr;
- testing.expect(length(ptr) == 2);
+ testing.expect(len(ptr) == 2);
}
}
@@ -1867,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);
diff --git a/lib/std/net.zig b/lib/std/net.zig
index b54803cd39..6d0daefdc0 100644
--- a/lib/std/net.zig
+++ b/lib/std/net.zig
@@ -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,
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 24d78bec9a..127ada8fe5 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -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);
diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig
index 1f11fabca0..e0c2636df1 100644
--- a/lib/std/special/c.zig
+++ b/lib/std/special/c.zig
@@ -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 {
diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig
index b33c758c38..8efc0e3746 100644
--- a/src-self-hosted/translate_c.zig
+++ b/src-self-hosted/translate_c.zig
@@ -4849,7 +4849,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{
diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig
index 681f5be500..44a8334b5d 100644
--- a/test/stage1/behavior/misc.zig
+++ b/test/stage1/behavior/misc.zig
@@ -335,7 +335,7 @@ test "string concatenation" {
comptime expect(@TypeOf(a) == *const [12:0]u8);
comptime expect(@TypeOf(b) == *const [12:0]u8);
- const len = mem.len(u8, b);
+ const len = mem.len(b);
const len_with_null = len + 1;
{
var i: u32 = 0;
From 00be934569d25e3b041091ff63a4cf6c456d1403 Mon Sep 17 00:00:00 2001
From: xackus <14938807+xackus@users.noreply.github.com>
Date: Tue, 25 Feb 2020 21:29:56 +0100
Subject: [PATCH 62/62] short std.builtin enum literals in std lib
---
lib/std/build.zig | 8 +--
lib/std/crypto/benchmark.zig | 2 +-
lib/std/elf.zig | 4 +-
lib/std/hash/auto_hash.zig | 8 +--
lib/std/hash/benchmark.zig | 2 +-
lib/std/hash/cityhash.zig | 8 +--
lib/std/hash/murmur.zig | 16 ++---
lib/std/hash_map.zig | 2 +-
lib/std/io.zig | 28 ++++----
lib/std/math/pow.zig | 2 +-
lib/std/math/powi.zig | 2 +-
lib/std/mem.zig | 96 ++++++++++++-------------
lib/std/special/compiler_rt/ashlti3.zig | 2 +-
lib/std/special/compiler_rt/ashrti3.zig | 2 +-
lib/std/special/compiler_rt/lshrti3.zig | 2 +-
lib/std/special/compiler_rt/multi3.zig | 2 +-
lib/std/special/compiler_rt/udivmod.zig | 4 +-
lib/std/testing.zig | 6 +-
lib/std/valgrind.zig | 4 +-
19 files changed, 97 insertions(+), 103 deletions(-)
diff --git a/lib/std/build.zig b/lib/std/build.zig
index 3ca59ae4cb..ecf3930551 100644
--- a/lib/std/build.zig
+++ b/lib/std/build.zig
@@ -1898,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");
diff --git a/lib/std/crypto/benchmark.zig b/lib/std/crypto/benchmark.zig
index 44326bfd97..0cc2c1d3ad 100644
--- a/lib/std/crypto/benchmark.zig
+++ b/lib/std/crypto/benchmark.zig
@@ -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.
diff --git a/lib/std/elf.zig b/lib/std/elf.zig
index 99084f1897..fc57db7c98 100644
--- a/lib/std/elf.zig
+++ b/lib/std/elf.zig
@@ -370,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,
};
diff --git a/lib/std/hash/auto_hash.zig b/lib/std/hash/auto_hash.zig
index 1bd7dfc05b..2c6b37e3db 100644
--- a/lib/std/hash/auto_hash.zig
+++ b/lib/std/hash/auto_hash.zig
@@ -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.
diff --git a/lib/std/hash/benchmark.zig b/lib/std/hash/benchmark.zig
index ed1bab9d87..4762b65afb 100644
--- a/lib/std/hash/benchmark.zig
+++ b/lib/std/hash/benchmark.zig
@@ -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 {
diff --git a/lib/std/hash/cityhash.zig b/lib/std/hash/cityhash.zig
index 18b3abe16d..a717303090 100644
--- a/lib/std/hash/cityhash.zig
+++ b/lib/std/hash/cityhash.zig
@@ -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);
}
diff --git a/lib/std/hash/murmur.zig b/lib/std/hash/murmur.zig
index 23b11ef284..96efc8b9c1 100644
--- a/lib/std/hash/murmur.zig
+++ b/lib/std/hash/murmur.zig
@@ -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);
}
diff --git a/lib/std/hash_map.zig b/lib/std/hash_map.zig
index 80ca218df6..4b3e082f0c 100644
--- a/lib/std/hash_map.zig
+++ b/lib/std/hash_map.zig
@@ -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 {
diff --git a/lib/std/io.zig b/lib/std/io.zig
index 6a2a080ef5..d0bf26d548 100644
--- a/lib/std/io.zig
+++ b/lib/std/io.zig
@@ -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);
},
}
diff --git a/lib/std/math/pow.zig b/lib/std/math/pow.zig
index 4f623377e6..ac6aee4cce 100644
--- a/lib/std/math/pow.zig
+++ b/lib/std/math/pow.zig
@@ -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;
}
diff --git a/lib/std/math/powi.zig b/lib/std/math/powi.zig
index d80700e5cd..ce3a3713e3 100644
--- a/lib/std/math/powi.zig
+++ b/lib/std/math/powi.zig
@@ -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) {
diff --git a/lib/std/mem.zig b/lib/std/mem.zig
index a6c4d0057e..391d587dbc 100644
--- a/lib/std/mem.zig
+++ b/lib/std/mem.zig
@@ -746,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));
@@ -779,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
@@ -809,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.
@@ -892,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.
@@ -950,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.
@@ -967,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" {
@@ -1506,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);
@@ -1578,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));
@@ -1617,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));
@@ -1651,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);
@@ -1692,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);
diff --git a/lib/std/special/compiler_rt/ashlti3.zig b/lib/std/special/compiler_rt/ashlti3.zig
index 211515f9dd..e3bc60bbb9 100644
--- a/lib/std/special/compiler_rt/ashlti3.zig
+++ b/lib/std/special/compiler_rt/ashlti3.zig
@@ -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,
diff --git a/lib/std/special/compiler_rt/ashrti3.zig b/lib/std/special/compiler_rt/ashrti3.zig
index 1bcd40d2e4..1cbe24fdeb 100644
--- a/lib/std/special/compiler_rt/ashrti3.zig
+++ b/lib/std/special/compiler_rt/ashrti3.zig
@@ -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,
diff --git a/lib/std/special/compiler_rt/lshrti3.zig b/lib/std/special/compiler_rt/lshrti3.zig
index 043be5e2a2..e1c2bb5bd3 100644
--- a/lib/std/special/compiler_rt/lshrti3.zig
+++ b/lib/std/special/compiler_rt/lshrti3.zig
@@ -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,
diff --git a/lib/std/special/compiler_rt/multi3.zig b/lib/std/special/compiler_rt/multi3.zig
index f46bd55421..eba58c45fc 100644
--- a/lib/std/special/compiler_rt/multi3.zig
+++ b/lib/std/special/compiler_rt/multi3.zig
@@ -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,
diff --git a/lib/std/special/compiler_rt/udivmod.zig b/lib/std/special/compiler_rt/udivmod.zig
index 1cf2589b16..9f0fb7d50f 100644
--- a/lib/std/special/compiler_rt/udivmod.zig
+++ b/lib/std/special/compiler_rt/udivmod.zig
@@ -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;
diff --git a/lib/std/testing.zig b/lib/std/testing.zig
index 398a71ff37..4f527ba700 100644
--- a/lib/std/testing.zig
+++ b/lib/std/testing.zig
@@ -63,15 +63,11 @@ pub fn expectEqual(expected: var, actual: @TypeOf(expected)) void {
.Pointer => |pointer| {
switch (pointer.size) {
- .One,
- .Many,
- .C,
- => {
+ .One, .Many, .C => {
if (actual != expected) {
std.debug.panic("expected {*}, found {*}", .{ expected, actual });
}
},
-
.Slice => {
if (actual.ptr != expected.ptr) {
std.debug.panic("expected slice ptr {}, found {}", .{ expected.ptr, actual.ptr });
diff --git a/lib/std/valgrind.zig b/lib/std/valgrind.zig
index fe1eb65b7a..38c4a491e0 100644
--- a/lib/std/valgrind.zig
+++ b/lib/std/valgrind.zig
@@ -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