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 7de45ebcd3649b6a49b6493fab55f8e84a96bd01..895cfa334cd73f740fcdafe11be7044a83389633 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 0000000000000000000000000000000000000000..c6c45c008ac171d2b589dffb38704cdcb5bb9d56
--- /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 0000000000000000000000000000000000000000..53d953765b074e308ef7dc789405a8922db2c1af
--- /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 0000000000000000000000000000000000000000..95814cda3d1edd4b6e33e08149dd14405d188075
--- /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 0000000000000000000000000000000000000000..f2d44b2dc060d6a6819ebcdd5501085939b135ae
--- /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 });
+}
--
2.54.0
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 022a34038ea5dafadd428d4a1f55e8dd124721e0..7277d0435992d5b5071fdbeb482fc96e8f2e3b9f 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;
};
--
2.54.0
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 5440de4d3ba20c6482a8def907d8f2cb2fd87a4c..1bb8fd85ae081e7929bbedc10e2a08976868cdd8 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 cf83bb1f7a84ef88655911b38a2e6e4dfb588044..84056eae0288ec5fc49e16ba205d7ad9b95d5337 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,
- };
- }
-
- pub fn getArch(self: Target) Cpu.Arch {
- return self.getCpu().arch;
+ return self.cpu;
}
+ /// Deprecated; access the `abi` field directly.
pub fn getAbi(self: Target) Abi {
- switch (self) {
- .Native => return builtin.abi,
- .Cross => |t| return t.abi,
- }
+ return self.abi;
+ }
+
+ pub fn getArch(self: Target) Cpu.Arch {
+ 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 9b776da930f91d0ed3b2ba7db79fd88a33f37c85..ceb232c79d21b603066afda2191c581972094694 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 e9fdde2e4bf16a014824091563ef0a2d2217015a..60008a2bc6c3a58b2c1c022ae17c5be796a2a505 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,
},
},
--
2.54.0
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 29837d56d9ecd19b658f6b3edc18bde09b26569e..6c89e7b9d117967ce598b35fbfc8e36e80c53a89 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 75809bde03660e225690e280cccd95efaa4f54d7..eacf408ba90f63dffb5870e3aa0f9bac8c6c5805 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 1bb8fd85ae081e7929bbedc10e2a08976868cdd8..3204ce905ec0ce77c16535a7307dbeda5c3b6fdc 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 f6c0e07dbd94c8421343dac74c6ce89c45b15034..9072d2c7cdd9b01ce5e612ea6bd8c8688175d3ee 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 0f7abaaaa00c8d3104b5dd859d3987952ba2544f..be32536d6f5bc31754b04f950c53a7ac65266456 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 bb8ed2e8a0b0ae4960a1d269c66466de72f9382d..d5e914b28632c10cf876e06174d2175329f65af0 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 765e0a45cf8e44933b854967c956af31a27e1b44..4057d4b62b1dc85f00d4515e779839dcc3184f7f 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 343df9bde0a49a014098341bf57b3c27ba4dfb31..558b7e051372c2d5cacb391a89972e126d1ad07a 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 409dace20fd0080f03377d38369885c93fd278fd..34f45894fbe99be9a9f7a7c7fddc57cfb1a4c2b7 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 9e4c1ac5f6edb930d2d0170d5feebdb5155607fa..007a01bb9000633e82f2219057b45ed506eb64e4 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 fd70f73aabf6fee17480c3050a63ce788eb56c47..3c5b48d047419b67787fdfa0788dd5d7d48bf012 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 492582da75c5948c721b775d42a1fd07a7fd4be0..51a63e90eed7ca85f8b5e932ac4d5fb0575e9241 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 e1b3495e5c152ab93ca596fef23b611c5cd5c448..b9cbb5d95fd02969aa0474b6aa71689d61df4594 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 085e56fc15a16892550670e91867141c7e146cb2..80ba5a79b53dfdbe188205004e4144d18567db98 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 ecd2c2b750638e0fce3b66889ba9e5ed5760533d..5077c52cd99445a107e26a88da758fb279efae45 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 9d0ffcfd4a6ba4a09dc0e4de1e5fd6f0559b1cd4..c243eeb62cfb96ef984f7a54a12f25178bf5b6b2 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 35c02654353ed134cdb37a6817afdea051bff1a2..31aab590d8b00142ab5a2a167ff0a2cf4b5f98ad 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 5d1c775629175c0bd0fe06ce6977b5fd46041e33..35bc9b53b0103fd1d2af843a6d52dad6b0ca8adf 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 0ff8c47ecf3c9de7df8561cd9d717ddfeda46776..1eb5a97ff164f800f6d5e873cdfd0919b1bcdde0 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 4295f1393ddca5069a45e416b76d4c039e2983f9..65809e97b4e70588cad01b53f0e390db50c08856 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 548f119b4f2c714079588af4a8bd0ce07e9e796f..6a2a080ef516a2a5301337b8d7dde28342dbcf72 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 6954b2fb171f5b02697ca1e035f2a04e54a95f7e..a57519cd14b249e9c70825ba01fc87da5338cd9a 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 898ba086beb216dc1d5073dc6b39fc560f657ec6..b54803cd39a69fe69f0a90bc478ef6ac5d6fe6d6 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 45d8b1cffdbb2a7db4ca2b2b7db01951ae3913de..4f3d955f30efbbdfb760ca6254988e11a9785979 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 3b60a08cef67b93557f1c8034a69eebed37a8550..6e96413d787941571bfadb6e766bf40310d0f376 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 bab9ad0ae5038b92c7e66f632e70b87db9453651..38f019d775a199030aa98889f2e6b28adb3dcb21 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 d11f206482cc26eb80176dfe08ed05bb22c9ca3c..30dba85e518665ece82b38a7ba35580afeaaf995 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 488a557ed6e4ac92b0a45ad1ef9a084a2f7758db..197edd82c134090a7023cee19a319d63b419021f 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 63b6fffa7394ef8e9dbf1a6fa7fc26550ccc27cb..51be01315e3f9e0e2172ab7ab78623928f67d696 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 0dab8bb64ba4310a227ea4202c7619fa64c61652..118b5d9ab43f90a04420c1714eec95c460f3f9c7 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 b31906c5f8b3e8cfb387497420cb98b0a47b67a4..c28db809ca8db66fd686c7a86ef09fbb7ede8def 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 56ae3d0d8ffb635e3c655596a4ac964479f21176..1f11fabca009439a175bfa56ea5ede6a059b3425 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 8d49fdbd2a26691ce22e9a24d138334fbcb9fa15..3126e81b9dd0ffe85002c82674173ca2e358d523 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 aa2faae90119b0599c7480c0cb77d8021c469f37..e2664f6bae12de67100d023598080764ec27dc5c 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 1a3239a95cf6ecc427eaf8347fa96fc42f81c8a4..0af08e9a84f77ab7516c28c710c8ccc4022a1aa0 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 b58b6e8144354e475e8e83bcdc12c94b414a8f18..b8e3e97f942d87bf89c34feea80b04663ab1e394 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 84056eae0288ec5fc49e16ba205d7ad9b95d5337..c9f8a247fed2e46616d7c547a2b2dbedf0c7737b 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 fcc71ae5a5b5635f5a59e676f51713a254d3065f..55db9d1733d1086f2f7e0cd9413ce92b89f53f68 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 63d3ecce18eb6a93b9cfe96ac7960424bf87688c..4112fb7bdaac870805976b83223e2bfbfce77171 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 3931e362c6c3270528f2a15c1cac71af44d8f4a8..5c9b71001b7a2e35728f75efc18397b8caaaa88c 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 2a840372b9a5a17021bf07621627e37b3a9710a1..1ee27c75968b469e9b8ffebb0e28a11d1fba45c2 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 d2db306be8d86c4fef2cc3b24feccc6858dd8116..bdaa8b86dc595eed940e394c8654de520a4726d5 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 11838e7e633e384fdd065df86f5c00a123907fe2..c7f5690cc3938acb51539897b6e2521966018e13 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 85740240ababd2fb89947d9b6c0131e0e3eac08f..d617abb8217e129cef3585f3a61f8eacb4f1bc44 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 0a29da4778500d60e9cb981d8e1840e99dabc498..1efa15574a788435b8ad42793035a1a710e8913b 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 fbfd1e26425fe184a656fa841b9c6955e0b62a37..264a896f466811a9e551487caf507e72e36b4d35 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 16f1891164ea4fe80e3b3563522127b4e69f5b09..be024a2a04e41b8aca25deb66592d90fd63f74d4 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 dacdb86bcd79009f6b661d398ad9894a1366022b..7f0f35abe044851863664fc6ccce1f72a31f104a 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 04c5420d26703c9d21c5838d7faa8ff409746610..2a7bf4d9cc6387f7eef0ccc730e49c26304d96bc 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 ee3e05a80139df97d4853c05228ec4b562870119..15122d5e118a8567aebc495b120c54f3c93f0d29 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 730c6e71935cc567e9beebac64fcec278943f2fe..2e92a982174958c6f103d06bdaeaea62eac6d29c 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 a4ab719123405d96e622671970472a7885f2e555..11612402eef2a1c0dd0006582288a82f999e2ede 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 736f11622ec43fa8ca11c39a98fef973bb8902f4..2023b45aafcc85d7e6b508b36b79a044b9225371 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 e6db241e882c9560f4a2c6d58a23db6ea12de31f..96222e3138ffb6f803e57b82dd8c544d300d56de 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 d1404c6f45517904cd6f447b7fc059433d7ca056..170ad3325d8ad5bd7e626adc7a0e99a84fbdb68b 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 c799ba484968b5612eebb3b03a7b660da8d50dd0..d6e07e7a56887f2d5b6610338247bc238a5e460a 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 4c4fc4eefea30ac89f75d7d070e927a5ea425b9e..8c5c19d733e22222d318de4dd1970043e00678a7 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 e89399c5e257aa9a1b6207b997c7331b8104d94c..01e5ac1fb8b69e37e94cbda2f5a045da7ab66e9f 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 60008a2bc6c3a58b2c1c022ae17c5be796a2a505..c088aafc5f3a0b8721c362ee7798073112df19b5 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,
--
2.54.0
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 31bac4ee24f7f5f215c19cbad56f467be9f1f075..cddecc202541ee97d0976367cbd8fb0168d92c25 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 4a1699b7821b64c34398ef23e0075d2b86fd0ec0..47841af5dcfeeba8642112c82bfd5778ada86183 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 849aac6c77841f243f671f65fa0a871281688bcc..91e2f9dfc110264812df281a151e79ebe0cdd73f 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 42c209937198712fc3d7f161e162746037eebd3c..8e4c7888ad85909126069754a325daa8e09f3eff 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);
--
2.54.0
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 6c89e7b9d117967ce598b35fbfc8e36e80c53a89..25f7d536b162908bb88ef1bfccab2529c264480f 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 3d1bdad677c827cdade119e15f952e69df89e1e7..90e95be5e1db568479b325369510eb0ef3b9939a 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 aa6e4143366a70fb55acaa6d749c6f0118a628e3..c62d614a6fdc12b372e5035e445d040e8132aed1 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 dae8940016cef207f29264998f085ac8a4bb7466..f1840b49e3cb65003fd928205a04447cedc68657 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 61692283e633b8b44651a21891e12be95c331e39..2635962fccca7986c955f3329068d48df2dd0cc0 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 eeac61915cd325e903e871b4b3f80bc32c026bbe..c51747fd12c2fd8de756e0fd34db863ca04cf531 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 4b7e69490a3a31880a829d1fc9024f1f41368600..2879c445028805de1eebe737cb253c160769ebad 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 6e96413d787941571bfadb6e766bf40310d0f376..9f349e7dc442c548d946578176497038bee7ac8a 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 402bb5a43c4c815ab23b7004321187da3f210f25..d7e175045c983dc3db29eba3120fcb2f322b8e85 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 4c43c90550ed76c354bf75d7eb91e444b8e0d353..cb4b94c5cd2d61cce57973ba8e8d8d27f1c59152 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 4eabd0c59466e23088014db3bf8d65fbac672535..96bb151e80e1d728ee14f92e7554cca7a4e51ab9 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 acda2f162bd976a822bdebf02fe449e3ac70748b..73cc0596e7b00a731611cef7bc9908719b963cbc 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 154fffe18a3cf27fad0d52e16b09e9591bc90891..02cef2f7008091cb38e1e977580c27ab26db48a8 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 af312ddc464419a26fb9420a0bc5f96c523f23bc..734efff4de9136825631bbaa2d1f3606566d0d4d 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 84dbf991e2cafaa9ddd2356f57e43e36998acc49..649fcdf1e3d905d72a1d290f1ae675e77a440456 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 0b2b5b958a60f7dedac07279e222078985093261..4601b90107269b103d20f1e43b2758c22c36eb80 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 8b99bbef5dc42767d23b9bf5e18eac68bda579e9..34c7407c981fe1774ff2058dbadc683631ba2f40 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 00db984a89e723587118022abf39d26c7bea1fa9..45baa62a171c68b95144798817d5a61949f5bdff 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 f14dbe6b4371d239a64911ee342eef6acaba0905..bd05c8652c28a2a14d17dd8df44fac6224a5c809 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 c9f8a247fed2e46616d7c547a2b2dbedf0c7737b..9007771c1a5e7d5ebd1d993152d3660b6fe78635 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 d617abb8217e129cef3585f3a61f8eacb4f1bc44..41def3812670d3d1361dc906acf6b0604e06a72f 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 8c727e87b56e0a9bbeba0fd673b7181291c97548..86209bd034d4202a28ce9d2970b95575e79f5cd6 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 91c17d88076763c6384ec0b7e6247c3fc301caac..7c1eb6d409eaf36f42ed717b2a159b676d74c575 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 21aa92537cd52cac50fcc4ce9c455e8324ba5223..968f09eeb8f775fe8211a6d8828248b8ddedf4de 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 fd4ff69964aae5f96b09b97781bdc52641d813d3..ab1156c3cbfc5986665fa98da76ebb7d3ec6e2f0 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 65a7d9e1f1dff6c118b8067c336b99093f218de9..e657b5472b0f6f0e48b54bc85f2228d2188c6871 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 2c5b9c790e7a6ef356fb52d56e57b54291c244be..aec9c827264e81b0b52c5a1947dd3cb9a6c2a0f5 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 c088aafc5f3a0b8721c362ee7798073112df19b5..78eaf562730bbf8d8cc3ad39b7df28395d1bb2b7 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 701513153c908cb927c9e66f2fb217d5f5463612..07364fb0321ca5e8a4e3982da1866ab8eef857c0 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",
--
2.54.0
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 | 296 +++++--------
lib/std/build/translate_c.zig | 14 +-
lib/std/builtin.zig | 23 +
lib/std/target.zig | 737 ++++++++++----------------------
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 | 204 ++++-----
test/translate_c.zig | 36 +-
14 files changed, 1311 insertions(+), 962 deletions(-)
create mode 100644 lib/std/zig/cross_target.zig
diff --git a/build.zig b/build.zig
index e1ae5cf3cdd5873df3ae40423b9b8f63708d8ddb..32694afb0ace878ba2715d7dc70259cdfff4163f 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 b429c93e65f7be26ab458b252d25f33d031ec6bf..9b8aca18d0fd960378be2f13a003aeaea1717982 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 25f7d536b162908bb88ef1bfccab2529c264480f..92b06a026169fd741eabee994d108077544ec9b0 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;
+ }
+ }
+ 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);
}
- 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
+ // 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);
+ 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);
- 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);
- }
+ for (all_features) |feature, i_usize| {
+ const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);
+ const in_cpu_set = populated_cpu_features.isEnabled(i);
+ const in_actual_set = cross.cpu.features.isEnabled(i);
+ if (in_cpu_set and !in_actual_set) {
+ try mcpu_buffer.appendByte('-');
+ try mcpu_buffer.append(feature.name);
+ } else if (!in_cpu_set and in_actual_set) {
+ try mcpu_buffer.appendByte('+');
+ try mcpu_buffer.append(feature.name);
}
- try zig_args.append(mcpu_buffer.toSliceConst());
}
- },
- }
-
- if (self.target_glibc) |ver| {
- try zig_args.append("-target-glibc");
- try zig_args.append(builder.fmt("{}.{}.{}", .{ ver.major, ver.minor, ver.patch }));
+ 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 90e95be5e1db568479b325369510eb0ef3b9939a..e9e61b190f6e28d4b1ad3db72c4898708038669a 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 3204ce905ec0ce77c16535a7307dbeda5c3b6fdc..de37fda903eafc51f1b0749f0b2610cde39889d0 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 9007771c1a5e7d5ebd1d993152d3660b6fe78635..440f50b811b4f2ff02ad59f0a1bb1dec8cc28564 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,126 +220,57 @@ 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 };
- }
- };
- const d_range = VersionRange.default(tag);
- 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 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),
};
}
+
+ pub fn requiresLibC(os: Os) bool {
+ return switch (os.tag) {
+ .freebsd,
+ .netbsd,
+ .macosx,
+ .ios,
+ .tvos,
+ .watchos,
+ .dragonfly,
+ .openbsd,
+ => true,
+
+ .linux,
+ .windows,
+ .freestanding,
+ .ananas,
+ .cloudabi,
+ .fuchsia,
+ .kfreebsd,
+ .lv2,
+ .solaris,
+ .haiku,
+ .minix,
+ .rtems,
+ .nacl,
+ .cnk,
+ .aix,
+ .cuda,
+ .nvcl,
+ .amdhsa,
+ .ps4,
+ .elfiamcu,
+ .mesa3d,
+ .contiki,
+ .amdpal,
+ .hermit,
+ .hurd,
+ .wasi,
+ .emscripten,
+ .uefi,
+ .other,
+ => false,
+ };
+ }
};
pub const aarch64 = @import("target/aarch64.zig");
@@ -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",
-
- .arm,
- .armeb,
- .thumb,
- .thumbeb,
- .aarch64_32,
- => "arm",
-
- .aarch64,
- .aarch64_be,
- => "arm64",
-
- 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 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) });
}
- 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 linuxTriple(self: Target, allocator: *mem.Allocator) ![:0]u8 {
+ return linuxTripleSimple(allocator, self.cpu.arch, self.os.tag, self.abi);
}
- 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 fn oFileExt(self: Target) [:0]const u8 {
+ return self.abi.oFileExt();
}
- 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;
+ 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 "";
+ },
}
- 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 exeFileExt(self: Target) [:0]const u8 {
+ return exeFileExtSimple(self.cpu.arch, self.os.tag);
}
- 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 348f651a883ec50aa8abfea4af1b619eeaa3cde4..398a71ff374667f2b248ca9e00d6d934d190799f 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 d76ed9dfd28af6c109c75e7d33fd30a4503783f3..81f34b09c97f7ec886aa9ea33e44f6b7f41f1581 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 0000000000000000000000000000000000000000..e785c4007369544ccf9bca2873928dab29587d97
--- /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 7f0f35abe044851863664fc6ccce1f72a31f104a..ecaad0daf2c040e21a0572f3d3ed6b94d5af0122 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,
- };
+ 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 7c1eb6d409eaf36f42ed717b2a159b676d74c575..979bf45bbe8254bd51431e381b852ce006c84d21 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 968f09eeb8f775fe8211a6d8828248b8ddedf4de..9a6bd0d3234457eef6b89414e923adc21cf29ba8 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 78eaf562730bbf8d8cc3ad39b7df28395d1bb2b7..9cf4e7bd9879af7cd89fb33ffdaedbdde45df60b 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,
- },
+ .target = .{
+ .cpu_arch = .x86_64,
+ .os_tag = .linux,
+ .abi = .musl,
},
.link_libc = true,
},
TestTarget{
- .target = Target{
- .Cross = .{
- .cpu = std.Target.Cpu.baseline(.i386),
- .os = std.Target.Os.defaultVersionRange(.linux),
- .abi = .none,
- },
+ .target = .{
+ .cpu_arch = .i386,
+ .os_tag = .linux,
+ .abi = .none,
},
},
TestTarget{
- .target = Target{
- .Cross = .{
- .cpu = std.Target.Cpu.baseline(.i386),
- .os = std.Target.Os.defaultVersionRange(.linux),
- .abi = .musl,
- },
+ .target = .{
+ .cpu_arch = .i386,
+ .os_tag = .linux,
+ .abi = .musl,
},
.link_libc = true,
},
TestTarget{
- .target = Target{
- .Cross = .{
- .cpu = std.Target.Cpu.baseline(.aarch64),
- .os = std.Target.Os.defaultVersionRange(.linux),
- .abi = .none,
- },
+ .target = .{
+ .cpu_arch = .aarch64,
+ .os_tag = .linux,
+ .abi = .none,
},
},
TestTarget{
- .target = Target{
- .Cross = .{
- .cpu = std.Target.Cpu.baseline(.aarch64),
- .os = std.Target.Os.defaultVersionRange(.linux),
- .abi = .musl,
- },
+ .target = .{
+ .cpu_arch = .aarch64,
+ .os_tag = .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 = .aarch64,
+ .os_tag = .linux,
+ .abi = .gnu,
},
.link_libc = true,
},
TestTarget{
- .target = .{
- .Cross = std.Target.parse(.{
- .arch_os_abi = "arm-linux-none",
- .cpu_features = "generic+v8a",
- }) catch unreachable,
- },
+ .target = CrossTarget.parse(.{
+ .arch_os_abi = "arm-linux-none",
+ .cpu_features = "generic+v8a",
+ }) catch unreachable,
},
TestTarget{
- .target = .{
- .Cross = std.Target.parse(.{
- .arch_os_abi = "arm-linux-musleabihf",
- .cpu_features = "generic+v8a",
- }) catch unreachable,
- },
+ .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 07364fb0321ca5e8a4e3982da1866ab8eef857c0..1d6c2a60aed7f22515a9a61774dde0ada884d7f1 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",
--
2.54.0
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 ceb232c79d21b603066afda2191c581972094694..2c8244d05394a4c7ad5d8f3b7d2cf4e91ec1544b 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);
--
2.54.0
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 e785c4007369544ccf9bca2873928dab29587d97..6654635b891bba12f4d23c88229f4e2069351abe 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 ecaad0daf2c040e21a0572f3d3ed6b94d5af0122..b2963c8a7145016fe381b1e432f105aaa382d7f6 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,
--
2.54.0
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 92b06a026169fd741eabee994d108077544ec9b0..792781df85894b2f753756114ec31fe956a17ef6 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 0b7410f2ade2cb09b1e4667277ceda1b2cbd996b..fd71588c5f18ba5901cfa635f897aff9b632a1a4 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();
--
2.54.0
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 792781df85894b2f753756114ec31fe956a17ef6..23db4c3f8ec2d94aeea0a533799bf4f019bf7186 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 6654635b891bba12f4d23c88229f4e2069351abe..1e160728150d87af828f87f7b694ef4269edaef9 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 b2963c8a7145016fe381b1e432f105aaa382d7f6..351c6c53576c5db7285a3d22af7242729d5fa6d9 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 ab1156c3cbfc5986665fa98da76ebb7d3ec6e2f0..b16bf485c0b9f9cad985174ca4df6510adcd93cf 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",
--
2.54.0
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 351c6c53576c5db7285a3d22af7242729d5fa6d9..61068f1737901af087df5d2631eed2897f6b295d 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;
}
--
2.54.0
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 1e160728150d87af828f87f7b694ef4269edaef9..fac90ddba8c5391ec629f02302eafda05dcbce25 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.
--
2.54.0
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 440f50b811b4f2ff02ad59f0a1bb1dec8cc28564..110aa2dcffd226a3fa8bb0d343a5891f0f79b3d6 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"),
--
2.54.0
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 61068f1737901af087df5d2631eed2897f6b295d..e7265ef6d3a47ad5bf218b85db6ac9a3cedf2ed7 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),
--
2.54.0
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 23db4c3f8ec2d94aeea0a533799bf4f019bf7186..7852828f7c3977ebdde717f409d353dade652701 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;
}
--
2.54.0
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 3126e81b9dd0ffe85002c82674173ca2e358d523..9ed866f62dbcc9bd461d4ffb217aeff6e2c45848 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 });
--
2.54.0
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 7c83c66ec06d23e5b017e89b0285a0e4536d9968..cba5b85264113648152a59527c2ba88ab7490484 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);
--
2.54.0
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 110aa2dcffd226a3fa8bb0d343a5891f0f79b3d6..9cd65e766193d08e08e3f4839d447b23b38837da 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,
}
}
};
--
2.54.0
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 b7d03d9e21f4b76bd3c8ab1c313554c1b6e3b611..bc5a29be449a3c273dc971cce1f31dc35a2f5018 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 7a41d46f5423c926e80d0053737ecd22553b16b0..ec89af35f855b3150901f6c2e9828f250b873564 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
--
2.54.0
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 9b8aca18d0fd960378be2f13a003aeaea1717982..83d1a6617971d1013a5c8ff534a59039dc428666 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", .{});
},
--
2.54.0
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 e7265ef6d3a47ad5bf218b85db6ac9a3cedf2ed7..14673b0e98ec42d9115895c45401359966a390a4 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,
};
}
--
2.54.0
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 83d1a6617971d1013a5c8ff534a59039dc428666..5d7f2b7b382eb20914de95e522b820b9769c7e97 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 e244d69e25a97e06f0d88fd62312f5d42413a73f..c10fc3ed3072dcb8f9c52bca25b3d0be1fc3bd9e 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");
--
2.54.0
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 9cd65e766193d08e08e3f4839d447b23b38837da..33019b6bbe004778cb325300af073a4f2dc65ec4 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 5c9b71001b7a2e35728f75efc18397b8caaaa88c..d2828a88a1519e27de465e4faf82a9fd384ea3e2 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 14673b0e98ec42d9115895c45401359966a390a4..5358c4fedc36f077671afa5bf13356c415bd044c 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;
}
--
2.54.0
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 118b5d9ab43f90a04420c1714eec95c460f3f9c7..01b9947518d57478bf5eea0c3dcb23ae3b57a943 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 33019b6bbe004778cb325300af073a4f2dc65ec4..379ae72afee5f3c3b42425447fb74bc7bdb3f863 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 d2828a88a1519e27de465e4faf82a9fd384ea3e2..e8c95f51255ee994e20771d33f976ca2b93e80ca 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 5358c4fedc36f077671afa5bf13356c415bd044c..cd3f49edfab497ee63da6b1668f348183b5d3383 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;
}
--
2.54.0
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 9072d2c7cdd9b01ce5e612ea6bd8c8688175d3ee..9d7d9524d6438994935435d9a9475a384f7750d0 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 34f45894fbe99be9a9f7a7c7fddc57cfb1a4c2b7..0d14f8d032609056c1a76445ca0b8d937485d3d9 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 007a01bb9000633e82f2219057b45ed506eb64e4..99084f18974115a6a97aab45c6aadca79aab66ae 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 e8c95f51255ee994e20771d33f976ca2b93e80ca..fe2f4c7e04db3bf83f0e85a21ead9a2bbe6454a7 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;
+ }
}
}
-}
+};
--
2.54.0
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 5f35540dc0d0301f54d46913f3840bc6e216f335..c6a70af56d66687007bca367c89e7ced94666077 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 379ae72afee5f3c3b42425447fb74bc7bdb3f863..a72bd921b0d6d2b3bbe68df31f29dd71d8e4961a 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 11612402eef2a1c0dd0006582288a82f999e2ede..f741cafd400eda97539bab27512b3f0c34583609 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 2023b45aafcc85d7e6b508b36b79a044b9225371..bc8e65fd56a76dce84aeadee64439af3b84bda93 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 8a68afbd83c4a89c25b8343ca8fd80d0d9f5333e..4df2cfca853e4167b3b63e718cf681735e2b6c47 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 9396eb262310da99017b3a7fa168007137eb176a..e72b6a6f4967783af06e228994a6f5df7034c672 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);
--
2.54.0
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 a72bd921b0d6d2b3bbe68df31f29dd71d8e4961a..6ecb679f298e87f081d61a709a99c5e1b828050b 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 fac90ddba8c5391ec629f02302eafda05dcbce25..c7fd1f04640d7ab54b38dd701e46806790f6823a 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 cd3f49edfab497ee63da6b1668f348183b5d3383..3dae15056ebf61019b8e5a299c3aca5e35485f48 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 7277d0435992d5b5071fdbeb482fc96e8f2e3b9f..838709b9c07f1e80c1df72613e8e3764e188385e 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 15122d5e118a8567aebc495b120c54f3c93f0d29..8ae730616d289f32fe8b5be7df3788a73aac741a 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 6329c59a5e6d85bca38f7cc0714ed2575946af8e..191da9a04ba8e7d0dba03bc1eb600356d7e145cc 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 91e2f9dfc110264812df281a151e79ebe0cdd73f..da5c1d52909e16bef2732e3023af83a8ba583860 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 8e4c7888ad85909126069754a325daa8e09f3eff..c04dcb46295bc4cd42df0a7220dc9d7d44632333 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 901390feae4c09e13c0bb6f84a2564c2a19a0fba..588771d8bf5c1c0a1260110a0c9f1fbd664f5ca2 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 f741cafd400eda97539bab27512b3f0c34583609..f471bda374d93954fa6d044e9b2c9b55e09c0983 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 bc8e65fd56a76dce84aeadee64439af3b84bda93..67a518e1fa3234c7ae1fe6ce848c73b826f5a831 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 96222e3138ffb6f803e57b82dd8c544d300d56de..20311788b249474c76f13a35a3979fae4d6a0f4d 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 4df2cfca853e4167b3b63e718cf681735e2b6c47..96ac2e166662cce2e3b3dde4fd66c843ebdc31ba 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 e72b6a6f4967783af06e228994a6f5df7034c672..9c6e8ce46ec246fc18009dcef4b1efe04ad96ec7 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 bc5a29be449a3c273dc971cce1f31dc35a2f5018..117c714a29ba295111171a67b331d07ad1f55488 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 {
--
2.54.0
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 9d7d9524d6438994935435d9a9475a384f7750d0..48a3039f51c180de192400e56835a8baad846af3 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 9f349e7dc442c548d946578176497038bee7ac8a..49e88bf9c7ae6e2200ef684d800fe17cc2702451 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 fe2f4c7e04db3bf83f0e85a21ead9a2bbe6454a7..ffae5c6015716cc1203bb3739f6895b49a9b4b8f 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);
}
--
2.54.0
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 | 81 +++++++++++--------------------
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, 139 insertions(+), 129 deletions(-)
diff --git a/lib/std/build.zig b/lib/std/build.zig
index 7852828f7c3977ebdde717f409d353dade652701..3ca59ae4cb8ddbaac7cb0b3f367736f1dddbdbf7 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 6ecb679f298e87f081d61a709a99c5e1b828050b..3054c6046753020d4980f7ce25d6be4ba33093b4 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 c7fd1f04640d7ab54b38dd701e46806790f6823a..212bc8eb9a8f73ff02cc04da3207a16dd8e147cc 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 ffae5c6015716cc1203bb3739f6895b49a9b4b8f..44ff9af6742a7883ff86b52505d2357ba49cb0c3 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];
+ const ld = target.standardDynamicLinkerPath();
+ if (ld.get() == null) continue;
+
+ ld_info_list_buffer[ld_info_list_len] = .{
+ .ld = ld,
+ .abi = abi,
+ };
ld_info_list_len += 1;
-
- 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];
@@ -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 3dae15056ebf61019b8e5a299c3aca5e35485f48..726c65937e55c21c8fd599ebec09f47522d8af17 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 838709b9c07f1e80c1df72613e8e3764e188385e..9f6bfd80a582091f71a93a9ce40de8ded91bde2a 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 8ae730616d289f32fe8b5be7df3788a73aac741a..62f2c7a8bae5e773a41081987755c137cd306f60 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 588771d8bf5c1c0a1260110a0c9f1fbd664f5ca2..03534db3b22e98aeb886866d65c8a39cb43c8b26 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 f471bda374d93954fa6d044e9b2c9b55e09c0983..92d08bed4fc2ab70f0c93b7890cc0783dbc4a48a 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 67a518e1fa3234c7ae1fe6ce848c73b826f5a831..1f6cb2d6aa07ba9cf6d257f13b67d3529e8a4307 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 20311788b249474c76f13a35a3979fae4d6a0f4d..b73269f4e8782a06762fca3e7a713368335c02f9 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 96ac2e166662cce2e3b3dde4fd66c843ebdc31ba..f0030e05ac4a06ad596572f1d1e3c43be291a36d 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 9c6e8ce46ec246fc18009dcef4b1efe04ad96ec7..01f2c6b16845c5dea18a19ca5b211682fb786c24 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);
--
2.54.0
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 2c8244d05394a4c7ad5d8f3b7d2cf4e91ec1544b..90037a11911f612ed2e3edab7e4f1fe18aa43267 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) {
--
2.54.0
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 9b776da930f91d0ed3b2ba7db79fd88a33f37c85..98a93d03bbcc354919e1a6af02dc0eacf212fc97 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 8e70e97aaa1ba578979488d81c3dc5d07a0cff01..55ace6198cdbac8681fb2045659bfa40fee8031a 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();
+ }
+}
--
2.54.0
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 98a93d03bbcc354919e1a6af02dc0eacf212fc97..55e65ae2a10f626131e30f5f1ddbdfc9b3816ae3 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;
}
--
2.54.0
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 | 152 ++++++++++++++++++++++++++---------
src-self-hosted/stage2.zig | 50 ++++--------
3 files changed, 140 insertions(+), 80 deletions(-)
diff --git a/lib/std/zig/cross_target.zig b/lib/std/zig/cross_target.zig
index 212bc8eb9a8f73ff02cc04da3207a16dd8e147cc..7ce35a26dcf40b6effecbd893e7b659ebb16b4af 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 44ff9af6742a7883ff86b52505d2357ba49cb0c3..f31044b81108a4ddd254d87967a7f1d90cbfad2d 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 {
+ 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 => {},
+ }
+ }
+
+ 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,
},
- else => {},
+ .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);
+ 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 726c65937e55c21c8fd599ebec09f47522d8af17..bef13a08e9470a84ef961e83c09198e2aa32e024 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
--
2.54.0
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 7ce35a26dcf40b6effecbd893e7b659ebb16b4af..a2d265707bb2a242c94cae1b891ed4d180f7a31d 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 f31044b81108a4ddd254d87967a7f1d90cbfad2d..b712c7c0627b73b32589832d2694627535398345 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 bef13a08e9470a84ef961e83c09198e2aa32e024..696d7ea76027076e3038bcb104bd10898f85909f 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);
--
2.54.0
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 a2d265707bb2a242c94cae1b891ed4d180f7a31d..16c0a64f6b2a08790aef44695d7b76d3997a6530 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);
+ switch (self.cpu_model) {
+ .native => {
+ // This works when doing `zig build` because Zig generates a build executable using
+ // native CPU model & features. However this will not be accurate otherwise, and
+ // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`.
+ return Target.current.cpu;
+ },
+ .baseline => {
+ var adjusted_baseline = Target.Cpu.baseline(self.getCpuArch());
+ self.updateCpuFeatures(&adjusted_baseline.features);
+ return adjusted_baseline;
+ },
+ .determined_by_cpu_arch => if (self.cpu_arch == null) {
+ // This works when doing `zig build` because Zig generates a build executable using
+ // native CPU model & features. However this will not be accurate otherwise, and
+ // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`.
+ return Target.current.cpu;
+ } else {
+ var adjusted_baseline = Target.Cpu.baseline(self.getCpuArch());
+ self.updateCpuFeatures(&adjusted_baseline.features);
+ return adjusted_baseline;
+ },
+ .explicit => |model| {
+ var adjusted_model = model.toCpu(self.getCpuArch());
self.updateCpuFeatures(&adjusted_model.features);
return adjusted_model;
- } 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;
+ },
}
}
@@ -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 b712c7c0627b73b32589832d2694627535398345..5ff17bae233c65891e6fc923fda67e52f4d36c08 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 696d7ea76027076e3038bcb104bd10898f85909f..a8aa10d91e034b5ecdd472047f17bffd49c0eed2 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");
--
2.54.0
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 5ff17bae233c65891e6fc923fda67e52f4d36c08..aa8def32a90e58e94c9176a6141248a3ad70d5aa 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
--
2.54.0
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 16c0a64f6b2a08790aef44695d7b76d3997a6530..66b734484056577f109a7cd93b9b96e6784a86ed 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" });
--
2.54.0
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 66b734484056577f109a7cd93b9b96e6784a86ed..08a8d21fad3dddee4c59a3c864af822c39878df7 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",
--
2.54.0
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 3054c6046753020d4980f7ce25d6be4ba33093b4..5807ba65efc5d64aaa0aa800e33c4fa54ef3038e 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,
--
2.54.0
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 90037a11911f612ed2e3edab7e4f1fe18aa43267..1a9172c03060ba3a67566f1bb09a7a24d866a14e 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();
--
2.54.0
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 ee3e05a80139df97d4853c05228ec4b562870119..69220382cd359f22da01826d8d0e42a971b45714 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 895cfa334cd73f740fcdafe11be7044a83389633..72e247b75a5558b4c09d35b1bc98b3907f18cf01 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 e4ea7f52db8386a4c26af488a7aea9608ff0fa9d..e183c6979f14096c538ab9c54646e8ef3006acfe 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 c0fa723cfb5c4364d7d4b23c5b706abcce3e81e6..9dd57f474e677bd8caf5f5be4cf003355c61218e 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| {
--
2.54.0
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 5807ba65efc5d64aaa0aa800e33c4fa54ef3038e..00825105058ab7123005cca13328fa9753cec99e 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 {
--
2.54.0
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 4e153d40edb5e73c419d2a742a3106f4012dda10..761b5083735ab9ba65d8f8f7420aadc9c74ff6a9 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 e98a2e6a87de6dc9f091de6463d150b0a5ba6e4b..49e60803bc74138173acb09820d962e9c03e4b4a 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 aa8def32a90e58e94c9176a6141248a3ad70d5aa..333a5c39506ea965630597a580182fd9e30cae9e 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.
--
2.54.0
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 4e153d40edb5e73c419d2a742a3106f4012dda10..89e02fc7f17c10c29ba857610df81983273a4381 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,
--
2.54.0
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 333a5c39506ea965630597a580182fd9e30cae9e..b04fb1288584f08ef155c30b6549f3ef7d004e45 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;
--
2.54.0
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 89e02fc7f17c10c29ba857610df81983273a4381..923644b6462fb3f4176c14fa49aeb88b6f8f78e7 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 {
--
2.54.0
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 00825105058ab7123005cca13328fa9753cec99e..c810c01ec31b8dfc6d4735bec0207ce9516e6eb6 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 08a8d21fad3dddee4c59a3c864af822c39878df7..38ce6549f38f53a7dadd00ab386c5cd31b205eba 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);
--
2.54.0
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 b04fb1288584f08ef155c30b6549f3ef7d004e45..e76d2eaca1b44eac5fa2f8bcc5d551342be71783 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;
--
2.54.0
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 49e88bf9c7ae6e2200ef684d800fe17cc2702451..24d78bec9aaf6e2da353535874fffa68c4ec3605 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 aa8def32a90e58e94c9176a6141248a3ad70d5aa..234c1a6550d4856c9676d388a9864f464c0b2f46 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.
--
2.54.0
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 234c1a6550d4856c9676d388a9864f464c0b2f46..7e23410fa8949d56461188a28126b24979d1fb1d 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
--
2.54.0
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 55db9d1733d1086f2f7e0cd9413ce92b89f53f68..de9d580af700e1d0950b9f83aae421e2965dfb4b 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);
--
2.54.0
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 7e23410fa8949d56461188a28126b24979d1fb1d..37834b4412c2e26c405f996f49eeb963b8b30daf 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,
};
--
2.54.0
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 de9d580af700e1d0950b9f83aae421e2965dfb4b..b2f8a44a474d4e420937c99a7eed5cc946d426d4 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);
--
2.54.0
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 37834b4412c2e26c405f996f49eeb963b8b30daf..5767291de74718784d66ecce566649951382dcc6 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);
--
2.54.0
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 5767291de74718784d66ecce566649951382dcc6..df50b4a4c266c2b39a502ca7ae9b858616fac3de 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) {
--
2.54.0
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 8e0bcc433b89622772dc0d3ce5494c1d31623344..f65a578e179888a1e77216ec8434ace9e5fd61e2 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) {
--
2.54.0
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 | 21 +++++++++++++++++----
lib/std/meta.zig | 26 ++++++++++++++++++++++++++
src-self-hosted/main.zig | 14 +++++++-------
test/stage1/behavior/misc.zig | 2 +-
6 files changed, 58 insertions(+), 15 deletions(-)
diff --git a/lib/std/cstr.zig b/lib/std/cstr.zig
index 4057d4b62b1dc85f00d4515e779839dcc3184f7f..6b2407cb7daca80a457bb21ed4ebc37e7185cc06 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 d0931016461ecd0d770182330f37582792ffde27..97f2133d67fb5868eed8b67ae6103f702fbedc6f 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 a4b48bbc1c72e4006e0010a4e0ce81d29a8c48a5..e6ef7d675287a55984a9b4bc1c8703e17556aa33 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;
}
+/// 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 ptr[0..len(T, ptr) :0];
+ 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 58fd6b9da71e20e4f44f7f41355ba16a1b3fd2ff..65809abb5ca532dcba2609ab96a1af3303238bc1 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 264a896f466811a9e551487caf507e72e36b4d35..4446a974d4f398dd299bcb93b59f6ee1d3fac58d 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 681f5be500004425d96eff39056d50bb18929a29..e2513c3f4a98c27d52bdd796a9ee6aa500bba587 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;
--
2.54.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 6b2407cb7daca80a457bb21ed4ebc37e7185cc06..4057d4b62b1dc85f00d4515e779839dcc3184f7f 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 e6ef7d675287a55984a9b4bc1c8703e17556aa33..a4b48bbc1c72e4006e0010a4e0ce81d29a8c48a5 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 e2513c3f4a98c27d52bdd796a9ee6aa500bba587..681f5be500004425d96eff39056d50bb18929a29 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;
--
2.54.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 de37fda903eafc51f1b0749f0b2610cde39889d0..a4f0ef269f9d9fd7a798bf58ce047871aec8218e 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 a4b48bbc1c72e4006e0010a4e0ce81d29a8c48a5..775e999e0bd8013a4f145734c6377b0fcffadd82 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| {
--
2.54.0
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 4057d4b62b1dc85f00d4515e779839dcc3184f7f..9cb16b0ed31746495b1d4da7a65bfc2962d321a2 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 97f2133d67fb5868eed8b67ae6103f702fbedc6f..3729b7dc879a77ac7e03bf83ba4818ef1f87b37d 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 775e999e0bd8013a4f145734c6377b0fcffadd82..a6c4d0057ead1513996a1548e8c4f5ae48644b10 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 b54803cd39a69fe69f0a90bc478ef6ac5d6fe6d6..6d0daefdc0b67e90571dfe363b1203ae2c461c9c 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 24d78bec9aaf6e2da353535874fffa68c4ec3605..127ada8fe5e7ec6f23d1ed4a23c9c5d62a3dd6f3 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 1f11fabca009439a175bfa56ea5ede6a059b3425..e0c2636df1d1c5ba92a9efc2d0bd81bb6ff3c33f 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 b33c758c3806102fc06a223e2ad01d4458856d60..8efc0e37465e0aa6f5e563c188f587937768e731 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 681f5be500004425d96eff39056d50bb18929a29..44a8334b5d04481c31943c5a9652448465e5e9f3 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;
--
2.54.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 3ca59ae4cb8ddbaac7cb0b3f367736f1dddbdbf7..ecf39305519722495392b302b649e4d7029937a6 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 44326bfd97b2a66423fae963fa9c2f2ed9ab2033..0cc2c1d3ad709a39cfaf17aa8ff9b325967c845f 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 99084f18974115a6a97aab45c6aadca79aab66ae..fc57db7c9812aec7aef8dccc4425cc9aaacc5586 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 1bd7dfc05bc77358707f9a69e9c633ac8c244242..2c6b37e3db7832fa7bb66e8ad0209863200a0a7f 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 ed1bab9d878be2296c8812116a47a6c342c3f151..4762b65afb7357d2112205af0eb0ae8b312c3a78 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 18b3abe16d6c44a3e2b94cd317de8497aad247d9..a717303090ff521dafac1d96ccf5ee28a98299c1 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 23b11ef28475b9d0fea5e1e6d1387d20c3c6f0b6..96efc8b9c1eb26e984c95789678ad80bed5fee6c 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 80ca218df63b75796f37b6ea430a6e4765660272..4b3e082f0c9796d760c785881dff82140665c145 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 6a2a080ef516a2a5301337b8d7dde28342dbcf72..d0bf26d5487562a81b4668c4d681ffe973a141b0 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 4f623377e6d783665b92ea3467f39faade190f16..ac6aee4cce39197eb3974d6f147198db7036a589 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 d80700e5cdfbb4da4cba0033c56583df45ea9166..ce3a3713e3a800db9a0d96e417d2a612432ef251 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 a6c4d0057ead1513996a1548e8c4f5ae48644b10..391d587dbc9afeff43ac1399c481b71372b99b1d 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 211515f9ddd3ba73dd17b60ac9c095bd0a57f861..e3bc60bbb9c15fa3dcfca0f2a554a71c3f2b485a 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 1bcd40d2e4d2a9c86b2e936aab7d9bdc1dd55b07..1cbe24fdebf922cb439915cf536e6897a01d6adf 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 043be5e2a2966539ebc84739981d480fd9a342ac..e1c2bb5bd3720d02a013f8f465463ea3528f9544 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 f46bd55421d0cd1df9a6e1f4c19e4a2784538da2..eba58c45fc87545c01a5b7185a17f64d5a88fc10 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 1cf2589b161c656e9a5c7e3830290f59490f0835..9f0fb7d50f271764473daebd584a92769886068c 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 398a71ff374667f2b248ca9e00d6d934d190799f..4f527ba700ab99288309eec7fb8f5fe649ba5765 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 fe1eb65b7a03248f3829c2f2045c64de0bc6f3e2..38c4a491e0e1d5643596cd99f03c9f15a3d7b155 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
--
2.54.0