diff --git a/lib/std/build.zig b/lib/std/build.zig index dd602ba922..6ef7286f9b 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -971,433 +971,14 @@ test "builder.findProgram compiles" { _ = builder.findProgram([_][]const u8{}, [_][]const u8{}) catch null; } -pub const Version = struct { - major: u32, - minor: u32, - patch: u32, -}; +/// Deprecated. Use `builtin.Version`. +pub const Version = builtin.Version; -pub const CrossTarget = struct { - arch: builtin.Arch, - os: builtin.Os, - abi: builtin.Abi, -}; +/// Deprecated. Use `std.Target.Cross`. +pub const CrossTarget = std.Target.Cross; -pub const Target = union(enum) { - Native: void, - Cross: CrossTarget, - - pub fn zigTriple(self: Target, allocator: *Allocator) ![]u8 { - return std.fmt.allocPrint( - allocator, - "{}{}-{}-{}", - @tagName(self.getArch()), - Target.archSubArchName(self.getArch()), - @tagName(self.getOs()), - @tagName(self.getAbi()), - ); - } - - pub fn allocDescription(self: Target, allocator: *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 zigTripleNoSubArch(self: Target, allocator: *Allocator) ![]u8 { - return std.fmt.allocPrint( - allocator, - "{}-{}-{}", - @tagName(self.getArch()), - @tagName(self.getOs()), - @tagName(self.getAbi()), - ); - } - - pub fn linuxTriple(self: Target, allocator: *Allocator) ![]u8 { - return std.fmt.allocPrint( - allocator, - "{}-{}-{}", - @tagName(self.getArch()), - @tagName(self.getOs()), - @tagName(self.getAbi()), - ); - } - - pub fn parse(text: []const u8) !Target { - var it = mem.separate(text, "-"); - const arch_name = it.next() orelse return error.MissingArchitecture; - const os_name = it.next() orelse return error.MissingOperatingSystem; - const abi_name = it.next(); - - var cross = CrossTarget{ - .arch = try parseArchSub(arch_name), - .os = try parseOs(os_name), - .abi = undefined, - }; - cross.abi = if (abi_name) |n| try parseAbi(n) else defaultAbi(cross.arch, cross.os); - return Target{ .Cross = cross }; - } - - pub fn defaultAbi(arch: builtin.Arch, target_os: builtin.Os) builtin.Abi { - switch (arch) { - .wasm32, .wasm64 => return .musl, - else => {}, - } - switch (target_os) { - .freestanding, - .ananas, - .cloudabi, - .dragonfly, - .lv2, - .solaris, - .haiku, - .minix, - .rtems, - .nacl, - .cnk, - .aix, - .cuda, - .nvcl, - .amdhsa, - .ps4, - .elfiamcu, - .mesa3d, - .contiki, - .amdpal, - .zen, - .hermit, - => return .eabi, - .openbsd, - .macosx, - .freebsd, - .ios, - .tvos, - .watchos, - .fuchsia, - .kfreebsd, - .netbsd, - .hurd, - => return .gnu, - .windows, - .uefi, - => return .msvc, - .linux, - .wasi, - .emscripten, - => return .musl, - } - } - - pub const ParseArchSubError = error{ - UnknownArchitecture, - UnknownSubArchitecture, - }; - - pub fn parseArchSub(text: []const u8) ParseArchSubError!builtin.Arch { - const info = @typeInfo(builtin.Arch); - inline for (info.Union.fields) |field| { - if (mem.eql(u8, text, field.name)) { - if (field.field_type == void) { - return (builtin.Arch)(@field(builtin.Arch, field.name)); - } else { - const sub_info = @typeInfo(field.field_type); - inline for (sub_info.Enum.fields) |sub_field| { - const combined = field.name ++ sub_field.name; - if (mem.eql(u8, text, combined)) { - return @unionInit(builtin.Arch, field.name, @field(field.field_type, sub_field.name)); - } - } - return error.UnknownSubArchitecture; - } - } - } - return error.UnknownArchitecture; - } - - pub fn parseOs(text: []const u8) !builtin.Os { - const info = @typeInfo(builtin.Os); - inline for (info.Enum.fields) |field| { - if (mem.eql(u8, text, field.name)) { - return @field(builtin.Os, field.name); - } - } - return error.UnknownOperatingSystem; - } - - pub fn parseAbi(text: []const u8) !builtin.Abi { - const info = @typeInfo(builtin.Abi); - inline for (info.Enum.fields) |field| { - if (mem.eql(u8, text, field.name)) { - return @field(builtin.Abi, field.name); - } - } - return error.UnknownApplicationBinaryInterface; - } - - fn archSubArchName(arch: builtin.Arch) []const u8 { - return switch (arch) { - .arm => |sub| @tagName(sub), - .armeb => |sub| @tagName(sub), - .thumb => |sub| @tagName(sub), - .thumbeb => |sub| @tagName(sub), - .aarch64 => |sub| @tagName(sub), - .aarch64_be => |sub| @tagName(sub), - .kalimba => |sub| @tagName(sub), - else => "", - }; - } - - pub fn subArchName(self: Target) []const u8 { - switch (self) { - .Native => return archSubArchName(builtin.arch), - .Cross => |cross| return archSubArchName(cross.arch), - } - } - - pub fn oFileExt(self: Target) []const u8 { - return switch (self.getAbi()) { - builtin.Abi.msvc => ".obj", - else => ".o", - }; - } - - pub fn exeFileExt(self: Target) []const u8 { - if (self.isWindows()) { - return ".exe"; - } else if (self.isUefi()) { - return ".efi"; - } else if (self.isWasm()) { - return ".wasm"; - } else { - return ""; - } - } - - pub fn staticLibSuffix(self: Target) []const u8 { - if (self.isWasm()) { - return ".wasm"; - } - switch (self.getAbi()) { - .msvc => return ".lib", - else => return ".a", - } - } - - pub fn dynamicLibSuffix(self: Target) []const u8 { - if (self.isDarwin()) { - return ".dylib"; - } - switch (self.getOs()) { - .windows => return ".dll", - else => return ".so", - } - } - - pub fn libPrefix(self: Target) []const u8 { - if (self.isWasm()) { - return ""; - } - switch (self.getAbi()) { - .msvc => return "", - else => return "lib", - } - } - - pub fn getOs(self: Target) builtin.Os { - return switch (self) { - .Native => builtin.os, - .Cross => |t| t.os, - }; - } - - pub fn getArch(self: Target) builtin.Arch { - switch (self) { - .Native => return builtin.arch, - .Cross => |t| return t.arch, - } - } - - pub fn getAbi(self: Target) builtin.Abi { - switch (self) { - .Native => return builtin.abi, - .Cross => |t| return t.abi, - } - } - - pub fn isMinGW(self: Target) bool { - return self.isWindows() and self.isGnu(); - } - - pub fn isGnu(self: Target) bool { - return switch (self.getAbi()) { - .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true, - else => false, - }; - } - - pub fn isDarwin(self: Target) bool { - return switch (self.getOs()) { - .ios, .macosx, .watchos, .tvos => true, - else => false, - }; - } - - pub fn isWindows(self: Target) bool { - return switch (self.getOs()) { - .windows => true, - else => false, - }; - } - - pub fn isLinux(self: Target) bool { - return switch (self.getOs()) { - .linux => true, - else => false, - }; - } - - pub fn isUefi(self: Target) bool { - return switch (self.getOs()) { - .uefi => true, - else => false, - }; - } - - pub fn isWasm(self: Target) bool { - return switch (self.getArch()) { - .wasm32, .wasm64 => true, - else => false, - }; - } - - pub fn isFreeBSD(self: Target) bool { - return switch (self.getOs()) { - .freebsd => true, - else => false, - }; - } - - pub fn isNetBSD(self: Target) bool { - return switch (self.getOs()) { - .netbsd => true, - else => false, - }; - } - - pub fn wantSharedLibSymLinks(self: Target) bool { - return !self.isWindows(); - } - - pub fn osRequiresLibC(self: Target) bool { - return self.isDarwin() or self.isFreeBSD() or self.isNetBSD(); - } - - pub fn getArchPtrBitWidth(self: Target) u32 { - switch (self.getArch()) { - .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, - } - } - - pub const Executor = union(enum) { - native, - qemu: []const u8, - wine: []const u8, - unavailable, - }; - - pub fn getExternalExecutor(self: Target) Executor { - if (@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) { - return switch (self.getArch()) { - .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, - }; - } - - if (self.isWindows()) { - switch (self.getArchPtrBitWidth()) { - 32 => return Executor{ .wine = "wine" }, - 64 => return Executor{ .wine = "wine64" }, - else => return .unavailable, - } - } - - return .unavailable; - } -}; +/// Deprecated. Use `std.Target`. +pub const Target = std.Target; const Pkg = struct { name: []const u8, @@ -2168,8 +1749,8 @@ pub const LibExeObjStep = struct { } switch (self.target) { - Target.Native => {}, - Target.Cross => { + .Native => {}, + .Cross => { try zig_args.append("-target"); try zig_args.append(self.target.zigTriple(builder.allocator) catch unreachable); }, @@ -2419,7 +2000,7 @@ pub const RunStep = struct { } pub fn addPathDir(self: *RunStep, search_path: []const u8) void { - const PATH = if (std.os.windows.is_the_target) "Path" else "PATH"; + const PATH = if (builtin.os == .windows) "Path" else "PATH"; const env_map = self.getEnvMap(); const prev_path = env_map.get(PATH) orelse { env_map.set(PATH, search_path) catch unreachable; diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig new file mode 100644 index 0000000000..8315cd84cf --- /dev/null +++ b/lib/std/builtin.zig @@ -0,0 +1,413 @@ +pub usingnamespace @import("builtin"); + +/// Deprecated: use `std.Target.Os`. +pub const Os = std.Target.Os; + +/// Deprecated: use `std.Target.Arch`. +pub const Arch = std.Target.Arch; + +/// Deprecated: use `std.Target.Abi`. +pub const Abi = std.Target.Abi; + +/// Deprecated: use `std.Target.ObjectFormat`. +pub const ObjectFormat = std.Target.ObjectFormat; + +/// Deprecated: use `std.Target.SubSystem`. +pub const SubSystem = std.Target.SubSystem; + +/// `explicit_subsystem` is missing when the subsystem is automatically detected, +/// so Zig standard library has the subsystem detection logic here. This should generally be +/// used rather than `explicit_subsystem`. +/// On non-Windows targets, this is `null`. +pub const subsystem: ?SubSystem = blk: { + if (@hasDecl(@This(), "explicit_subsystem")) break :blk explicit_subsystem; + switch (os) { + .windows => { + if (is_test) { + break :blk SubSystem.Console; + } + if (@hasDecl(root, "WinMain") or + @hasDecl(root, "wWinMain") or + @hasDecl(root, "WinMainCRTStartup") or + @hasDecl(root, "wWinMainCRTStartup")) + { + break :blk SubSystem.Windows; + } else { + break :blk SubSystem.Console; + } + }, + else => break :blk null, + } +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const StackTrace = struct { + index: usize, + instruction_addresses: []usize, +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const GlobalLinkage = enum { + Internal, + Strong, + Weak, + LinkOnce, +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const AtomicOrder = enum { + Unordered, + Monotonic, + Acquire, + Release, + AcqRel, + SeqCst, +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const AtomicRmwOp = enum { + Xchg, + Add, + Sub, + And, + Nand, + Or, + Xor, + Max, + Min, +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const Mode = enum { + Debug, + ReleaseSafe, + ReleaseFast, + ReleaseSmall, +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const TypeId = enum { + Type, + Void, + Bool, + NoReturn, + Int, + Float, + Pointer, + Array, + Struct, + ComptimeFloat, + ComptimeInt, + Undefined, + Null, + Optional, + ErrorUnion, + ErrorSet, + Enum, + Union, + Fn, + BoundFn, + ArgTuple, + Opaque, + Frame, + AnyFrame, + Vector, + EnumLiteral, +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const TypeInfo = union(TypeId) { + Type: void, + Void: void, + Bool: void, + NoReturn: void, + Int: Int, + Float: Float, + Pointer: Pointer, + Array: Array, + Struct: Struct, + ComptimeFloat: void, + ComptimeInt: void, + Undefined: void, + Null: void, + Optional: Optional, + ErrorUnion: ErrorUnion, + ErrorSet: ErrorSet, + Enum: Enum, + Union: Union, + Fn: Fn, + BoundFn: Fn, + ArgTuple: void, + Opaque: void, + Frame: void, + AnyFrame: AnyFrame, + Vector: Vector, + EnumLiteral: void, + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Int = struct { + is_signed: bool, + bits: comptime_int, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Float = struct { + bits: comptime_int, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Pointer = struct { + size: Size, + is_const: bool, + is_volatile: bool, + alignment: comptime_int, + child: type, + is_allowzero: bool, + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Size = enum { + One, + Many, + Slice, + C, + }; + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Array = struct { + len: comptime_int, + child: type, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const ContainerLayout = enum { + Auto, + Extern, + Packed, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const StructField = struct { + name: []const u8, + offset: ?comptime_int, + field_type: type, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Struct = struct { + layout: ContainerLayout, + fields: []StructField, + decls: []Declaration, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Optional = struct { + child: type, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const ErrorUnion = struct { + error_set: type, + payload: type, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Error = struct { + name: []const u8, + value: comptime_int, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const ErrorSet = ?[]Error; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const EnumField = struct { + name: []const u8, + value: comptime_int, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Enum = struct { + layout: ContainerLayout, + tag_type: type, + fields: []EnumField, + decls: []Declaration, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const UnionField = struct { + name: []const u8, + enum_field: ?EnumField, + field_type: type, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Union = struct { + layout: ContainerLayout, + tag_type: ?type, + fields: []UnionField, + decls: []Declaration, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const CallingConvention = enum { + Unspecified, + C, + Cold, + Naked, + Stdcall, + Async, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const FnArg = struct { + is_generic: bool, + is_noalias: bool, + arg_type: ?type, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Fn = struct { + calling_convention: CallingConvention, + is_generic: bool, + is_var_args: bool, + return_type: ?type, + args: []FnArg, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const AnyFrame = struct { + child: ?type, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Vector = struct { + len: comptime_int, + child: type, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Declaration = struct { + name: []const u8, + is_pub: bool, + data: Data, + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Data = union(enum) { + Type: type, + Var: type, + Fn: FnDecl, + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const FnDecl = struct { + fn_type: type, + inline_type: Inline, + calling_convention: CallingConvention, + is_var_args: bool, + is_extern: bool, + is_export: bool, + lib_name: ?[]const u8, + return_type: type, + arg_names: [][]const u8, + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Inline = enum { + Auto, + Always, + Never, + }; + }; + }; + }; +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const FloatMode = enum { + Strict, + Optimized, +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const Endian = enum { + Big, + Little, +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const Version = struct { + major: u32, + minor: u32, + patch: u32, +}; + +/// This function type is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const PanicFn = fn ([]const u8, ?*StackTrace) noreturn; + +/// This function is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const panic: PanicFn = if (@hasDecl(root, "panic")) root.panic else default_panic; + +/// This function is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn { + @setCold(true); + switch (os) { + .freestanding => { + while (true) { + @breakpoint(); + } + }, + .wasi => { + std.debug.warn("{}", msg); + _ = std.os.wasi.proc_raise(std.os.wasi.SIGABRT); + unreachable; + }, + .uefi => { + // TODO look into using the debug info and logging helpful messages + std.os.abort(); + }, + else => { + const first_trace_addr = @returnAddress(); + std.debug.panicExtra(error_return_trace, first_trace_addr, "{}", msg); + }, + } +} + +const std = @import("std.zig"); +const root = @import("root"); diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index f2e8120a0e..ebd12a0d86 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -36,7 +36,7 @@ const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header; /// export a weak symbol here, to be overridden by the real one. pub extern "c" var _mh_execute_header: mach_hdr = undefined; comptime { - if (std.os.darwin.is_the_target) { + if (std.Target.current.isDarwin()) { @export("_mh_execute_header", _mh_execute_header, .Weak); } } diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig index d786c3f4de..5fae9447a9 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 (os.windows.is_the_target) void else i32, - handle: if (os.windows.is_the_target) windows.HANDLE else void, - thread_handle: if (os.windows.is_the_target) windows.HANDLE else void, + 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, allocator: *mem.Allocator, @@ -39,16 +39,16 @@ pub const ChildProcess = struct { stderr_behavior: StdIo, /// Set to change the user id when spawning the child process. - uid: if (os.windows.is_the_target) void else ?u32, + uid: if (builtin.os == .windows) void else ?u32, /// Set to change the group id when spawning the child process. - gid: if (os.windows.is_the_target) void else ?u32, + gid: if (builtin.os == .windows) void else ?u32, /// Set to change the current working directory when spawning the child process. cwd: ?[]const u8, - err_pipe: if (os.windows.is_the_target) void else [2]os.fd_t, - llnode: if (os.windows.is_the_target) void else TailQueue(*ChildProcess).Node, + err_pipe: if (builtin.os == .windows) void else [2]os.fd_t, + llnode: if (builtin.os == .windows) void else TailQueue(*ChildProcess).Node, pub const SpawnError = error{OutOfMemory} || os.ExecveError || os.SetIdError || os.ChangeCurDirError || windows.CreateProcessError; @@ -82,8 +82,8 @@ pub const ChildProcess = struct { .term = null, .env_map = null, .cwd = null, - .uid = if (os.windows.is_the_target) {} else null, - .gid = if (os.windows.is_the_target) {} else null, + .uid = if (builtin.os == .windows) {} else null, + .gid = if (builtin.os == .windows) {} else null, .stdin = null, .stdout = null, .stderr = null, @@ -103,7 +103,7 @@ pub const ChildProcess = struct { /// On success must call `kill` or `wait`. pub fn spawn(self: *ChildProcess) !void { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { return self.spawnWindows(); } else { return self.spawnPosix(); @@ -117,7 +117,7 @@ pub const ChildProcess = struct { /// Forcibly terminates child process and then cleans up all resources. pub fn kill(self: *ChildProcess) !Term { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { return self.killWindows(1); } else { return self.killPosix(); @@ -147,7 +147,7 @@ pub const ChildProcess = struct { /// Blocks until child process terminates and then cleans up all resources. pub fn wait(self: *ChildProcess) !Term { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { return self.waitWindows(); } else { return self.waitPosix(); diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 0be778b3b6..95670dc4ea 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -133,7 +133,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 (windows.is_the_target) { + if (builtin.os == .windows) { const addrs = stack_trace.instruction_addresses; const u32_addrs_len = @intCast(u32, addrs.len); const first_addr = first_address orelse { @@ -310,7 +310,7 @@ pub const StackIterator = struct { }; pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void { - if (windows.is_the_target) { + if (builtin.os == .windows) { return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr); } var it = StackIterator.init(start_addr); @@ -342,10 +342,10 @@ pub fn writeCurrentStackTraceWindows( /// TODO once https://github.com/ziglang/zig/issues/3157 is fully implemented, /// make this `noasync fn` and remove the individual noasync calls. pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { - if (windows.is_the_target) { + if (builtin.os == .windows) { return noasync printSourceAtAddressWindows(debug_info, out_stream, address, tty_color); } - if (os.darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { return noasync printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color); } return noasync printSourceAtAddressPosix(debug_info, out_stream, address, tty_color); @@ -832,10 +832,10 @@ pub const OpenSelfDebugInfoError = error{ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo { if (builtin.strip_debug_info) return error.MissingDebugInfo; - if (windows.is_the_target) { + if (builtin.os == .windows) { return noasync openSelfDebugInfoWindows(allocator); } - if (os.darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { return noasync openSelfDebugInfoMacOs(allocator); } return noasync openSelfDebugInfoPosix(allocator); @@ -2364,7 +2364,7 @@ pub fn attachSegfaultHandler() void { if (!have_segfault_handling_support) { @compileError("segfault handler not supported for this target"); } - if (windows.is_the_target) { + if (builtin.os == .windows) { windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows); return; } @@ -2378,7 +2378,7 @@ pub fn attachSegfaultHandler() void { } fn resetSegfaultHandler() void { - if (windows.is_the_target) { + if (builtin.os == .windows) { if (windows_segfault_handle) |handle| { assert(windows.kernel32.RemoveVectoredExceptionHandler(handle) != 0); windows_segfault_handle = null; diff --git a/lib/std/event/channel.zig b/lib/std/event/channel.zig index 2f211d21e2..1092f2204a 100644 --- a/lib/std/event/channel.zig +++ b/lib/std/event/channel.zig @@ -307,7 +307,7 @@ test "std.event.Channel" { // https://github.com/ziglang/zig/issues/1908 if (builtin.single_threaded) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/3251 - if (std.os.freebsd.is_the_target) return error.SkipZigTest; + if (builtin.os == .freebsd) return error.SkipZigTest; var loop: Loop = undefined; // TODO make a multi threaded test diff --git a/lib/std/event/fs.zig b/lib/std/event/fs.zig index 81fd950e44..2f64d453af 100644 --- a/lib/std/event/fs.zig +++ b/lib/std/event/fs.zig @@ -909,7 +909,7 @@ fn hashString(s: []const u16) u32 { // var close_op_consumed = false; // defer if (!close_op_consumed) close_op.finish(); // -// const flags = if (os.darwin.is_the_target) os.O_SYMLINK | os.O_EVTONLY else 0; +// const flags = if (comptime std.Target.current.isDarwin()) os.O_SYMLINK | os.O_EVTONLY else 0; // const mode = 0; // const fd = try await (async openPosix(self.channel.loop, resolved_path, flags, mode) catch unreachable); // close_op.setHandle(fd); diff --git a/lib/std/event/future.zig b/lib/std/event/future.zig index 1e3508de41..c5376bc9f6 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 (std.os.freebsd.is_the_target) return error.SkipZigTest; + if (builtin.os == .freebsd) return error.SkipZigTest; const allocator = std.heap.direct_allocator; diff --git a/lib/std/event/lock.zig b/lib/std/event/lock.zig index a0b1fd3e50..fdcfd1e298 100644 --- a/lib/std/event/lock.zig +++ b/lib/std/event/lock.zig @@ -119,7 +119,7 @@ test "std.event.Lock" { // TODO https://github.com/ziglang/zig/issues/1908 if (builtin.single_threaded) return error.SkipZigTest; // TODO https://github.com/ziglang/zig/issues/3251 - if (std.os.freebsd.is_the_target) return error.SkipZigTest; + if (builtin.os == .freebsd) return error.SkipZigTest; const allocator = std.heap.direct_allocator; diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 3fdd175e77..5517f6f280 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -255,7 +255,7 @@ pub const AtomicFile = struct { assert(!self.finished); self.file.close(); self.finished = true; - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const dest_path_w = try os.windows.sliceToPrefixedFileW(self.dest_path); const tmp_path_w = try os.windows.cStrToPrefixedFileW(&self.tmp_path_buf); return os.renameW(&tmp_path_w, &dest_path_w); @@ -659,7 +659,7 @@ pub const Dir = struct { /// Closing the returned `Dir` is checked illegal behavior. /// On POSIX targets, this function is comptime-callable. pub fn cwd() Dir { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle }; } else { return Dir{ .fd = os.AT_FDCWD }; @@ -711,7 +711,7 @@ pub const Dir = struct { /// Call `close` on the result when done. pub fn openDir(self: Dir, sub_path: []const u8) OpenError!Dir { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); return self.openDirW(&sub_path_w); } @@ -722,7 +722,7 @@ pub const Dir = struct { /// Same as `openDir` except the parameter is null-terminated. pub fn openDirC(self: Dir, sub_path_c: [*]const u8) OpenError!Dir { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); return self.openDirW(&sub_path_w); } @@ -829,7 +829,7 @@ pub const Dir = struct { /// Returns `error.DirNotEmpty` if the directory is not empty. /// To delete a directory recursively, see `deleteTree`. pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); return self.deleteDirW(&sub_path_w); } @@ -1146,10 +1146,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 (os.linux.is_the_target) { + if (builtin.os == .linux) { return File.openReadC(c"/proc/self/exe"); } - if (os.windows.is_the_target) { + if (builtin.os == .windows) { var buf: [os.windows.PATH_MAX_WIDE]u16 = undefined; const wide_slice = try selfExePathW(&buf); return File.openReadW(wide_slice.ptr); @@ -1180,7 +1180,7 @@ pub const SelfExePathError = os.ReadLinkError || os.SysCtlError; /// been deleted, the file path looks something like `/a/b/c/exe (deleted)`. /// TODO make the return type of this a null terminated pointer pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 { - if (os.darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { var u32_len: u32 = out_buffer.len; const rc = std.c._NSGetExecutablePath(out_buffer, &u32_len); if (rc != 0) return error.NameTooLong; @@ -1228,7 +1228,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 (os.linux.is_the_target) { + if (builtin.os == .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 44992ff47d..06a26ed481 100644 --- a/lib/std/fs/file.zig +++ b/lib/std/fs/file.zig @@ -27,7 +27,7 @@ pub const File = struct { /// Call close to clean up. pub fn openRead(path: []const u8) OpenError!File { - if (windows.is_the_target) { + if (builtin.os == .windows) { const path_w = try windows.sliceToPrefixedFileW(path); return openReadW(&path_w); } @@ -37,7 +37,7 @@ pub const File = struct { /// `openRead` except with a null terminated path pub fn openReadC(path: [*]const u8) OpenError!File { - if (windows.is_the_target) { + if (builtin.os == .windows) { const path_w = try windows.cStrToPrefixedFileW(path); return openReadW(&path_w); } @@ -69,7 +69,7 @@ pub const File = struct { /// If a file already exists in the destination it will be truncated. /// Call close to clean up. pub fn openWriteMode(path: []const u8, file_mode: Mode) OpenError!File { - if (windows.is_the_target) { + if (builtin.os == .windows) { const path_w = try windows.sliceToPrefixedFileW(path); return openWriteModeW(&path_w, file_mode); } @@ -79,7 +79,7 @@ pub const File = struct { /// Same as `openWriteMode` except `path` is null-terminated. pub fn openWriteModeC(path: [*]const u8, file_mode: Mode) OpenError!File { - if (windows.is_the_target) { + if (builtin.os == .windows) { const path_w = try windows.cStrToPrefixedFileW(path); return openWriteModeW(&path_w, file_mode); } @@ -106,7 +106,7 @@ pub const File = struct { /// If a file already exists in the destination this returns OpenError.PathAlreadyExists /// Call close to clean up. pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File { - if (windows.is_the_target) { + if (builtin.os == .windows) { const path_w = try windows.sliceToPrefixedFileW(path); return openWriteNoClobberW(&path_w, file_mode); } @@ -115,7 +115,7 @@ pub const File = struct { } pub fn openWriteNoClobberC(path: [*]const u8, file_mode: Mode) OpenError!File { - if (windows.is_the_target) { + if (builtin.os == .windows) { const path_w = try windows.cStrToPrefixedFileW(path); return openWriteNoClobberW(&path_w, file_mode); } @@ -174,7 +174,7 @@ pub const File = struct { /// Test whether ANSI escape codes will be treated as such. pub fn supportsAnsiEscapeCodes(self: File) bool { - if (windows.is_the_target) { + if (builtin.os == .windows) { return os.isCygwinPty(self.handle); } if (self.isTty()) { @@ -214,7 +214,7 @@ pub const File = struct { } pub fn getEndPos(self: File) GetPosError!u64 { - if (windows.is_the_target) { + if (builtin.os == .windows) { return windows.GetFileSizeEx(self.handle); } return (try self.stat()).size; @@ -223,7 +223,7 @@ pub const File = struct { pub const ModeError = os.FStatError; pub fn mode(self: File) ModeError!Mode { - if (windows.is_the_target) { + if (builtin.os == .windows) { return {}; } return (try self.stat()).mode; @@ -246,7 +246,7 @@ pub const File = struct { pub const StatError = os.FStatError; pub fn stat(self: File) StatError!Stat { - if (windows.is_the_target) { + if (builtin.os == .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); @@ -291,7 +291,7 @@ pub const File = struct { /// last modification timestamp in nanoseconds mtime: i64, ) UpdateTimesError!void { - if (windows.is_the_target) { + if (builtin.os == .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/path.zig b/lib/std/fs/path.zig index 560d9b58f3..f337e1df9a 100644 --- a/lib/std/fs/path.zig +++ b/lib/std/fs/path.zig @@ -13,16 +13,16 @@ const process = std.process; pub const sep_windows = '\\'; pub const sep_posix = '/'; -pub const sep = if (windows.is_the_target) sep_windows else sep_posix; +pub const sep = if (builtin.os == .windows) sep_windows else sep_posix; pub const sep_str = [1]u8{sep}; pub const delimiter_windows = ';'; pub const delimiter_posix = ':'; -pub const delimiter = if (windows.is_the_target) delimiter_windows else delimiter_posix; +pub const delimiter = if (builtin.os == .windows) delimiter_windows else delimiter_posix; pub fn isSep(byte: u8) bool { - if (windows.is_the_target) { + if (builtin.os == .windows) { return byte == '/' or byte == '\\'; } else { return byte == '/'; @@ -72,7 +72,7 @@ fn joinSep(allocator: *Allocator, separator: u8, paths: []const []const u8) ![]u return buf; } -pub const join = if (windows.is_the_target) joinWindows else joinPosix; +pub const join = if (builtin.os == .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 isAbsolute(path: []const u8) bool { - if (windows.is_the_target) { + if (builtin.os == .windows) { return isAbsoluteWindows(path); } else { return isAbsolutePosix(path); @@ -327,7 +327,7 @@ test "windowsParsePath" { } pub fn diskDesignator(path: []const u8) []const u8 { - if (windows.is_the_target) { + if (builtin.os == .windows) { return diskDesignatorWindows(path); } else { return ""; @@ -392,7 +392,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 (windows.is_the_target) { + if (builtin.os == .windows) { return resolveWindows(allocator, paths); } else { return resolvePosix(allocator, paths); @@ -409,7 +409,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(windows.is_the_target); // resolveWindows called on non windows can't use getCwd + assert(builtin.os == .windows); // resolveWindows called on non windows can't use getCwd return process.getCwdAlloc(allocator); } @@ -504,7 +504,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { result_disk_designator = result[0..result_index]; }, WindowsPath.Kind.None => { - assert(windows.is_the_target); // resolveWindows called on non windows can't use getCwd + assert(builtin.os == .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); @@ -519,7 +519,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { }, } } else { - assert(windows.is_the_target); // resolveWindows called on non windows can't use getCwd + assert(builtin.os == .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); @@ -590,7 +590,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(!windows.is_the_target); // resolvePosix called on windows can't use getCwd + assert(builtin.os != .windows); // resolvePosix called on windows can't use getCwd return process.getCwdAlloc(allocator); } @@ -612,7 +612,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { if (have_abs) { result = try allocator.alloc(u8, max_size); } else { - assert(!windows.is_the_target); // resolvePosix called on windows can't use getCwd + assert(builtin.os != .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); @@ -653,7 +653,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { test "resolve" { const cwd = try process.getCwdAlloc(debug.global_allocator); - if (windows.is_the_target) { + if (builtin.os == .windows) { if (windowsParsePath(cwd).kind == WindowsPath.Kind.Drive) { cwd[0] = asciiUpper(cwd[0]); } @@ -669,7 +669,7 @@ test "resolveWindows" { // TODO https://github.com/ziglang/zig/issues/3288 return error.SkipZigTest; } - if (windows.is_the_target) { + if (builtin.os == .windows) { const cwd = try process.getCwdAlloc(debug.global_allocator); const parsed_cwd = windowsParsePath(cwd); { @@ -735,7 +735,7 @@ fn testResolvePosix(paths: []const []const u8) []u8 { /// 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 (windows.is_the_target) { + if (builtin.os == .windows) { return dirnameWindows(path); } else { return dirnamePosix(path); @@ -867,7 +867,7 @@ fn testDirnameWindows(input: []const u8, expected_output: ?[]const u8) void { } pub fn basename(path: []const u8) []const u8 { - if (windows.is_the_target) { + if (builtin.os == .windows) { return basenameWindows(path); } else { return basenamePosix(path); @@ -983,7 +983,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 (windows.is_the_target) { + if (builtin.os == .windows) { return relativeWindows(allocator, from, to); } else { return relativePosix(allocator, from, to); diff --git a/lib/std/heap.zig b/lib/std/heap.zig index f3a0d457d2..8723c7eab6 100644 --- a/lib/std/heap.zig +++ b/lib/std/heap.zig @@ -44,7 +44,7 @@ const DirectAllocator = struct { if (n == 0) return (([*]u8)(undefined))[0..0]; - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const w = os.windows; // Although officially it's at least aligned to page boundary, @@ -130,7 +130,7 @@ const DirectAllocator = 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 (os.windows.is_the_target) { + if (builtin.os == .windows) { const w = os.windows; if (new_size == 0) { // From the docs: @@ -170,7 +170,7 @@ const DirectAllocator = 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 (os.windows.is_the_target) { + if (builtin.os == .windows) { if (old_mem.len == 0) { return alloc(allocator, new_size, new_align); } diff --git a/lib/std/io.zig b/lib/std/io.zig index 7502601650..39c3a7cf9b 100644 --- a/lib/std/io.zig +++ b/lib/std/io.zig @@ -37,7 +37,7 @@ pub const is_async = mode != .blocking; pub const GetStdIoError = os.windows.GetStdHandleError; pub fn getStdOut() GetStdIoError!File { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const handle = try os.windows.GetStdHandle(os.windows.STD_OUTPUT_HANDLE); return File.openHandle(handle); } @@ -45,7 +45,7 @@ pub fn getStdOut() GetStdIoError!File { } pub fn getStdErr() GetStdIoError!File { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const handle = try os.windows.GetStdHandle(os.windows.STD_ERROR_HANDLE); return File.openHandle(handle); } @@ -53,7 +53,7 @@ pub fn getStdErr() GetStdIoError!File { } pub fn getStdIn() GetStdIoError!File { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const handle = try os.windows.GetStdHandle(os.windows.STD_INPUT_HANDLE); return File.openHandle(handle); } diff --git a/lib/std/math.zig b/lib/std/math.zig index cb9589e95d..9b56d0b8ce 100644 --- a/lib/std/math.zig +++ b/lib/std/math.zig @@ -202,7 +202,7 @@ pub const Complex = complex.Complex; pub const big = @import("math/big.zig"); -comptime { +test "" { std.meta.refAllDecls(@This()); } diff --git a/lib/std/os.zig b/lib/std/os.zig index 3f8daf0290..d239f198f4 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -23,10 +23,6 @@ const elf = std.elf; const dl = @import("dynamic_library.zig"); const MAX_PATH_BYTES = std.fs.MAX_PATH_BYTES; -comptime { - assert(@import("std") == std); // std lib tests require --override-lib-dir -} - pub const darwin = @import("os/darwin.zig"); pub const freebsd = @import("os/freebsd.zig"); pub const linux = @import("os/linux.zig"); @@ -36,6 +32,23 @@ pub const wasi = @import("os/wasi.zig"); pub const windows = @import("os/windows.zig"); pub const zen = @import("os/zen.zig"); +comptime { + assert(@import("std") == std); // std lib tests require --override-lib-dir +} + +test "" { + _ = darwin; + _ = freebsd; + _ = linux; + _ = netbsd; + _ = uefi; + _ = wasi; + _ = windows; + _ = zen; + + _ = @import("os/test.zig"); +} + /// When linking libc, this is the C API. Otherwise, it is the OS-specific system interface. pub const system = if (builtin.link_libc) std.c else switch (builtin.os) { .macosx, .ios, .watchos, .tvos => darwin, @@ -72,13 +85,13 @@ 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 (windows.is_the_target) { + if (builtin.os == .windows) { return windows.CloseHandle(fd); } - if (wasi.is_the_target) { + if (builtin.os == .wasi) { _ = wasi.fd_close(fd); } - if (darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { // This avoids the EINTR problem. switch (darwin.getErrno(darwin.@"close$NOCANCEL"(fd))) { EBADF => unreachable, // Always a race condition. @@ -100,12 +113,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 (windows.is_the_target) { + if (builtin.os == .windows) { return windows.RtlGenRandom(buffer); } - if (linux.is_the_target or freebsd.is_the_target) { + if (builtin.os == .linux or builtin.os == .freebsd) { var buf = buffer; - const use_c = !linux.is_the_target or + const use_c = builtin.os != .linux or std.c.versionCheck(builtin.Version{ .major = 2, .minor = 25, .patch = 0 }).ok; while (buf.len != 0) { @@ -132,7 +145,7 @@ pub fn getrandom(buffer: []u8) GetRandomError!void { } return; } - if (wasi.is_the_target) { + if (builtin.os == .wasi) { switch (wasi.random_get(buffer.ptr, buffer.len)) { 0 => return, else => |err| return unexpectedErrno(err), @@ -162,7 +175,7 @@ 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 (windows.is_the_target) { + if (builtin.os == .windows) { if (builtin.mode == .Debug) { @breakpoint(); } @@ -193,14 +206,14 @@ pub fn raise(sig: u8) RaiseError!void { } } - if (wasi.is_the_target) { + if (builtin.os == .wasi) { switch (wasi.proc_raise(SIGABRT)) { 0 => return, else => |err| return unexpectedErrno(err), } } - if (linux.is_the_target) { + if (builtin.os == .linux) { var set: linux.sigset_t = undefined; linux.blockAppSignals(&set); const tid = linux.syscall0(linux.SYS_gettid); @@ -232,16 +245,16 @@ pub fn exit(status: u8) noreturn { if (builtin.link_libc) { system.exit(status); } - if (windows.is_the_target) { + if (builtin.os == .windows) { windows.kernel32.ExitProcess(status); } - if (wasi.is_the_target) { + if (builtin.os == .wasi) { wasi.proc_exit(status); } - if (linux.is_the_target and !builtin.single_threaded) { + if (builtin.os == .linux and !builtin.single_threaded) { linux.exit_group(status); } - if (uefi.is_the_target) { + if (builtin.os == .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| { @@ -270,11 +283,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 (windows.is_the_target) { + if (builtin.os == .windows) { return windows.ReadFile(fd, buf); } - if (wasi.is_the_target and !builtin.link_libc) { + if (builtin.os == .wasi and !builtin.link_libc) { const iovs = [1]iovec{iovec{ .iov_base = buf.ptr, .iov_len = buf.len, @@ -314,7 +327,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { /// Number of bytes read is returned. Upon reading end-of-file, zero is returned. /// This function is for blocking file descriptors only. pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) ReadError!usize { - if (darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { // Darwin does not have preadv but it does have pread. var off: usize = 0; var iov_i: usize = 0; @@ -385,11 +398,11 @@ pub const WriteError = error{ /// Write to a file descriptor. Keeps trying if it gets interrupted. /// This function is for blocking file descriptors only. pub fn write(fd: fd_t, bytes: []const u8) WriteError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { return windows.WriteFile(fd, bytes); } - if (wasi.is_the_target and !builtin.link_libc) { + if (builtin.os == .wasi and !builtin.link_libc) { const ciovs = [1]iovec_const{iovec_const{ .iov_base = bytes.ptr, .iov_len = bytes.len, @@ -464,7 +477,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!void { /// This function is for blocking file descriptors only. For non-blocking, see /// `pwritevAsync`. pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) WriteError!void { - if (darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { // Darwin does not have pwritev but it does have pwrite. var off: usize = 0; var iov_i: usize = 0; @@ -828,7 +841,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 (windows.is_the_target) { + if (builtin.os == .windows) { return windows.GetCurrentDirectory(out_buffer); } @@ -869,7 +882,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 (windows.is_the_target) { + if (builtin.os == .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); @@ -883,7 +896,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: [*]const u8, sym_link_path: [*]const u8) SymLinkError!void { - if (windows.is_the_target) { + if (builtin.os == .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); @@ -958,7 +971,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 (windows.is_the_target) { + if (builtin.os == .windows) { const file_path_w = try windows.sliceToPrefixedFileW(file_path); return windows.DeleteFileW(&file_path_w); } else { @@ -969,7 +982,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: [*]const u8) UnlinkError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const file_path_w = try windows.cStrToPrefixedFileW(file_path); return windows.DeleteFileW(&file_path_w); } @@ -999,7 +1012,7 @@ pub const UnlinkatError = UnlinkError || error{ /// Delete a file name and possibly the file it refers to, based on an open directory handle. pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const file_path_w = try windows.sliceToPrefixedFileW(file_path); return unlinkatW(dirfd, &file_path_w, flags); } @@ -1009,7 +1022,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: [*]const u8, flags: u32) UnlinkatError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const file_path_w = try windows.cStrToPrefixedFileW(file_path_c); return unlinkatW(dirfd, &file_path_w, flags); } @@ -1063,7 +1076,6 @@ pub fn unlinkatW(dirfd: fd_t, sub_path_w: [*]const u16, flags: u32) UnlinkatErro return error.FileBusy; } - var attr = w.OBJECT_ATTRIBUTES{ .Length = @sizeOf(w.OBJECT_ATTRIBUTES), .RootDirectory = dirfd, @@ -1121,7 +1133,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 (windows.is_the_target) { + if (builtin.os == .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); @@ -1134,7 +1146,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: [*]const u8, new_path: [*]const u8) RenameError!void { - if (windows.is_the_target) { + if (builtin.os == .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); @@ -1189,7 +1201,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 (windows.is_the_target) { + if (builtin.os == .windows) { const dir_path_w = try windows.sliceToPrefixedFileW(dir_path); return windows.CreateDirectoryW(&dir_path_w, null); } else { @@ -1200,7 +1212,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: [*]const u8, mode: u32) MakeDirError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const dir_path_w = try windows.cStrToPrefixedFileW(dir_path); return windows.CreateDirectoryW(&dir_path_w, null); } @@ -1239,7 +1251,7 @@ pub const DeleteDirError = error{ /// Deletes an empty directory. pub fn rmdir(dir_path: []const u8) DeleteDirError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const dir_path_w = try windows.sliceToPrefixedFileW(dir_path); return windows.RemoveDirectoryW(&dir_path_w); } else { @@ -1250,7 +1262,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void { /// Same as `rmdir` except the parameter is null-terminated. pub fn rmdirC(dir_path: [*]const u8) DeleteDirError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const dir_path_w = try windows.cStrToPrefixedFileW(dir_path); return windows.RemoveDirectoryW(&dir_path_w); } @@ -1286,7 +1298,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 (windows.is_the_target) { + if (builtin.os == .windows) { const dir_path_w = try windows.sliceToPrefixedFileW(dir_path); @compileError("TODO implement chdir for Windows"); } else { @@ -1297,7 +1309,7 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void { /// Same as `chdir` except the parameter is null-terminated. pub fn chdirC(dir_path: [*]const u8) ChangeCurDirError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const dir_path_w = try windows.cStrToPrefixedFileW(dir_path); @compileError("TODO implement chdir for Windows"); } @@ -1328,7 +1340,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 (windows.is_the_target) { + if (builtin.os == .windows) { const file_path_w = try windows.sliceToPrefixedFileW(file_path); @compileError("TODO implement readlink for Windows"); } else { @@ -1339,7 +1351,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: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 { - if (windows.is_the_target) { + if (builtin.os == .windows) { const file_path_w = try windows.cStrToPrefixedFileW(file_path); @compileError("TODO implement readlink for Windows"); } @@ -1360,7 +1372,7 @@ pub fn readlinkC(file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 { } pub fn readlinkatC(dirfd: fd_t, file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 { - if (windows.is_the_target) { + if (builtin.os == .windows) { const file_path_w = try windows.cStrToPrefixedFileW(file_path); @compileError("TODO implement readlink for Windows"); } @@ -1428,7 +1440,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 (windows.is_the_target) { + if (builtin.os == .windows) { if (isCygwinPty(handle)) return true; @@ -1438,10 +1450,10 @@ pub fn isatty(handle: fd_t) bool { if (builtin.link_libc) { return system.isatty(handle) != 0; } - if (wasi.is_the_target) { + if (builtin.os == .wasi) { @compileError("TODO implement std.os.isatty for WASI"); } - if (linux.is_the_target) { + if (builtin.os == .linux) { var wsz: linux.winsize = undefined; return linux.syscall3(linux.SYS_ioctl, @bitCast(usize, isize(handle)), linux.TIOCGWINSZ, @ptrToInt(&wsz)) == 0; } @@ -1449,7 +1461,7 @@ pub fn isatty(handle: fd_t) bool { } pub fn isCygwinPty(handle: fd_t) bool { - if (!windows.is_the_target) return false; + if (builtin.os != .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); @@ -1949,7 +1961,7 @@ pub const FStatError = error{SystemResources} || UnexpectedError; pub fn fstat(fd: fd_t) FStatError!Stat { var stat: Stat = undefined; - if (darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { switch (darwin.getErrno(darwin.@"fstat$INODE64"(fd, &stat))) { 0 => return stat, EINVAL => unreachable, @@ -2215,7 +2227,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 (windows.is_the_target) { + if (builtin.os == .windows) { const path_w = try windows.sliceToPrefixedFileW(path); _ = try windows.GetFileAttributesW(&path_w); return; @@ -2226,7 +2238,7 @@ pub fn access(path: []const u8, mode: u32) AccessError!void { /// Same as `access` except `path` is null-terminated. pub fn accessC(path: [*]const u8, mode: u32) AccessError!void { - if (windows.is_the_target) { + if (builtin.os == .windows) { const path_w = try windows.cStrToPrefixedFileW(path); _ = try windows.GetFileAttributesW(&path_w); return; @@ -2346,7 +2358,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 (linux.is_the_target and !builtin.link_libc and @sizeOf(usize) == 4) { + if (builtin.os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) { var result: u64 = undefined; switch (errno(system.llseek(fd, offset, &result, SEEK_SET))) { 0 => return, @@ -2358,7 +2370,7 @@ pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void { else => |err| return unexpectedErrno(err), } } - if (windows.is_the_target) { + if (builtin.os == .windows) { return windows.SetFilePointerEx_BEGIN(fd, offset); } const ipos = @bitCast(i64, offset); // the OS treats this as unsigned @@ -2375,7 +2387,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 (linux.is_the_target and !builtin.link_libc and @sizeOf(usize) == 4) { + if (builtin.os == .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, @@ -2387,7 +2399,7 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void { else => |err| return unexpectedErrno(err), } } - if (windows.is_the_target) { + if (builtin.os == .windows) { return windows.SetFilePointerEx_CURRENT(fd, offset); } switch (errno(system.lseek(fd, offset, SEEK_CUR))) { @@ -2403,7 +2415,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 (linux.is_the_target and !builtin.link_libc and @sizeOf(usize) == 4) { + if (builtin.os == .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, @@ -2415,7 +2427,7 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void { else => |err| return unexpectedErrno(err), } } - if (windows.is_the_target) { + if (builtin.os == .windows) { return windows.SetFilePointerEx_END(fd, offset); } switch (errno(system.lseek(fd, offset, SEEK_END))) { @@ -2431,7 +2443,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 (linux.is_the_target and !builtin.link_libc and @sizeOf(usize) == 4) { + if (builtin.os == .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, @@ -2443,7 +2455,7 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 { else => |err| return unexpectedErrno(err), } } - if (windows.is_the_target) { + if (builtin.os == .windows) { return windows.SetFilePointerEx_CURRENT_get(fd); } const rc = system.lseek(fd, 0, SEEK_CUR); @@ -2492,7 +2504,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 (windows.is_the_target) { + if (builtin.os == .windows) { const pathname_w = try windows.sliceToPrefixedFileW(pathname); return realpathW(&pathname_w, out_buffer); } @@ -2502,11 +2514,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: [*]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { - if (windows.is_the_target) { + if (builtin.os == .windows) { const pathname_w = try windows.cStrToPrefixedFileW(pathname); return realpathW(&pathname_w, out_buffer); } - if (linux.is_the_target and !builtin.link_libc) { + if (builtin.os == .linux and !builtin.link_libc) { const fd = try openC(pathname, linux.O_PATH | linux.O_NONBLOCK | linux.O_CLOEXEC, 0); defer close(fd); @@ -2584,9 +2596,12 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void { } } -pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_info, size: usize, data: ?*T) i32, data: ?*T) isize { - // This is implemented only for systems using ELF executables - if (windows.is_the_target or builtin.os == .uefi or wasi.is_the_target or darwin.is_the_target) +pub fn dl_iterate_phdr( + comptime T: type, + callback: extern fn (info: *dl_phdr_info, size: usize, data: ?*T) i32, + data: ?*T, +) isize { + if (builtin.object_format != .elf) @compileError("dl_iterate_phdr is not available for this target"); if (builtin.link_libc) { @@ -2725,7 +2740,7 @@ pub const SigaltstackError = error{ } || UnexpectedError; pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void { - if (windows.is_the_target or uefi.is_the_target or wasi.is_the_target) + if (builtin.os == .windows or builtin.os == .uefi or builtin.os == .wasi) @compileError("std.os.sigaltstack not available for this target"); switch (errno(system.sigaltstack(ss, old_ss))) { @@ -2797,7 +2812,7 @@ pub fn gethostname(name_buffer: *[HOST_NAME_MAX]u8) GetHostNameError![]u8 { else => |err| return unexpectedErrno(err), } } - if (linux.is_the_target) { + if (builtin.os == .linux) { var uts: utsname = undefined; switch (errno(system.uname(&uts))) { 0 => { @@ -2813,16 +2828,3 @@ pub fn gethostname(name_buffer: *[HOST_NAME_MAX]u8) GetHostNameError![]u8 { @compileError("TODO implement gethostname for this OS"); } - -test "" { - _ = @import("os/darwin.zig"); - _ = @import("os/freebsd.zig"); - _ = @import("os/linux.zig"); - _ = @import("os/netbsd.zig"); - _ = @import("os/uefi.zig"); - _ = @import("os/wasi.zig"); - _ = @import("os/windows.zig"); - _ = @import("os/zen.zig"); - - _ = @import("os/test.zig"); -} diff --git a/lib/std/os/darwin.zig b/lib/std/os/darwin.zig index 0adf71affb..d3e9cefb86 100644 --- a/lib/std/os/darwin.zig +++ b/lib/std/os/darwin.zig @@ -1,8 +1,4 @@ const builtin = @import("builtin"); const std = @import("../std.zig"); -pub const is_the_target = switch (builtin.os) { - .macosx, .tvos, .watchos, .ios => true, - else => false, -}; pub usingnamespace std.c; pub usingnamespace @import("bits.zig"); diff --git a/lib/std/os/freebsd.zig b/lib/std/os/freebsd.zig index ddbf98f2bc..5f9684b96d 100644 --- a/lib/std/os/freebsd.zig +++ b/lib/std/os/freebsd.zig @@ -1,5 +1,3 @@ const std = @import("../std.zig"); -const builtin = @import("builtin"); -pub const is_the_target = builtin.os == .freebsd; pub usingnamespace std.c; pub usingnamespace @import("bits.zig"); diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index c91b6ad98b..2c8500574d 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -13,7 +13,6 @@ const elf = std.elf; const vdso = @import("linux/vdso.zig"); const dl = @import("../dynamic_library.zig"); -pub const is_the_target = builtin.os == .linux; pub usingnamespace switch (builtin.arch) { .x86_64 => @import("linux/x86_64.zig"), .aarch64 => @import("linux/arm64.zig"), @@ -1079,7 +1078,7 @@ pub fn io_uring_register(fd: i32, opcode: u32, arg: ?*const c_void, nr_args: u32 } test "" { - if (is_the_target) { + if (builtin.os == .linux) { _ = @import("linux/test.zig"); } } diff --git a/lib/std/os/netbsd.zig b/lib/std/os/netbsd.zig index d484e7374b..5f9684b96d 100644 --- a/lib/std/os/netbsd.zig +++ b/lib/std/os/netbsd.zig @@ -1,5 +1,3 @@ -const builtin = @import("builtin"); const std = @import("../std.zig"); -pub const is_the_target = builtin.os == .netbsd; pub usingnamespace std.c; pub usingnamespace @import("bits.zig"); diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index b6e6728142..1d61548396 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 (os.windows.is_the_target) { + } else if (builtin.os == .windows) { expect(Thread.getCurrentId() != thread_current_id); } else { // If the thread completes very quickly, then thread_id can be 0. See the @@ -212,7 +212,7 @@ test "dl_iterate_phdr" { } test "gethostname" { - if (os.windows.is_the_target) + if (builtin.os == .windows) return error.SkipZigTest; var buf: [os.HOST_NAME_MAX]u8 = undefined; @@ -221,7 +221,7 @@ test "gethostname" { } test "pipe" { - if (os.windows.is_the_target) + if (builtin.os == .windows) return error.SkipZigTest; var fds = try os.pipe(); diff --git a/lib/std/os/uefi.zig b/lib/std/os/uefi.zig index f42dae5fad..31d4d2ed50 100644 --- a/lib/std/os/uefi.zig +++ b/lib/std/os/uefi.zig @@ -1,16 +1,15 @@ /// A protocol is an interface identified by a GUID. pub const protocols = @import("uefi/protocols.zig"); + /// Status codes returned by EFI interfaces pub const status = @import("uefi/status.zig"); pub const tables = @import("uefi/tables.zig"); const fmt = @import("std").fmt; -const builtin = @import("builtin"); -pub const is_the_target = builtin.os == .uefi; - /// The EFI image's handle that is passed to its entry point. pub var handle: Handle = undefined; + /// A pointer to the EFI System Table that is passed to the EFI image's entry point. pub var system_table: *tables.SystemTable = undefined; @@ -50,26 +49,35 @@ pub const Handle = *@OpaqueType(); pub const Time = extern struct { /// 1900 - 9999 year: u16, + /// 1 - 12 month: u8, + /// 1 - 31 day: u8, + /// 0 - 23 hour: u8, + /// 0 - 59 minute: u8, + /// 0 - 59 second: u8, _pad1: u8, + /// 0 - 999999999 nanosecond: u32, + /// The time's offset in minutes from UTC. /// Allowed values are -1440 to 1440 or unspecified_timezone timezone: i16, daylight: packed struct { _pad1: u6, + /// If true, the time has been adjusted for daylight savings time. in_daylight: bool, + /// If true, the time is affected by daylight savings time. adjust_daylight: bool, }, @@ -83,8 +91,10 @@ pub const Time = extern struct { pub const TimeCapabilities = extern struct { /// Resolution in Hz resolution: u32, + /// Accuracy in an error rate of 1e-6 parts per million. accuracy: u32, + /// If true, a time set operation clears the device's time below the resolution level. sets_to_zero: bool, }; diff --git a/lib/std/os/wasi.zig b/lib/std/os/wasi.zig index 57b708395c..fce29ef0b3 100644 --- a/lib/std/os/wasi.zig +++ b/lib/std/os/wasi.zig @@ -1,10 +1,8 @@ // Based on https://github.com/CraneStation/wasi-sysroot/blob/wasi/libc-bottom-half/headers/public/wasi/core.h // and https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md -const builtin = @import("builtin"); const std = @import("std"); const assert = std.debug.assert; -pub const is_the_target = builtin.os == .wasi; pub usingnamespace @import("bits.zig"); comptime { diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 6c4aeb4cef..c8c99c6a59 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -11,7 +11,6 @@ const assert = std.debug.assert; const math = std.math; const maxInt = std.math.maxInt; -pub const is_the_target = builtin.os == .windows; pub const advapi32 = @import("windows/advapi32.zig"); pub const kernel32 = @import("windows/kernel32.zig"); pub const ntdll = @import("windows/ntdll.zig"); @@ -22,32 +21,6 @@ pub usingnamespace @import("windows/bits.zig"); pub const self_process_handle = @intToPtr(HANDLE, maxInt(usize)); -/// `builtin` is missing `subsystem` when the subsystem is automatically detected, -/// so Zig standard library has the subsystem detection logic here. This should generally be -/// used rather than `builtin.subsystem`. -/// On non-windows targets, this is `null`. -pub const subsystem: ?builtin.SubSystem = blk: { - if (@hasDecl(builtin, "subsystem")) break :blk builtin.subsystem; - switch (builtin.os) { - .windows => { - if (builtin.is_test) { - break :blk builtin.SubSystem.Console; - } - const root = @import("root"); - if (@hasDecl(root, "WinMain") or - @hasDecl(root, "wWinMain") or - @hasDecl(root, "WinMainCRTStartup") or - @hasDecl(root, "wWinMainCRTStartup")) - { - break :blk builtin.SubSystem.Windows; - } else { - break :blk builtin.SubSystem.Console; - } - }, - else => break :blk null, - } -}; - pub const CreateFileError = error{ SharingViolation, PathAlreadyExists, diff --git a/lib/std/process.zig b/lib/std/process.zig index c74e8c43be..fca10a240d 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -39,7 +39,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { var result = BufMap.init(allocator); errdefer result.deinit(); - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const ptr = try os.windows.GetEnvironmentStringsW(); defer os.windows.FreeEnvironmentStringsW(ptr); @@ -129,7 +129,7 @@ pub const GetEnvVarOwnedError = error{ /// Caller must free returned memory. /// TODO make this go through libc when we have it pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key); defer allocator.free(key_with_null); diff --git a/lib/std/special/panic.zig b/lib/std/special/panic.zig deleted file mode 100644 index f42085126b..0000000000 --- a/lib/std/special/panic.zig +++ /dev/null @@ -1,31 +0,0 @@ -// This file is the default panic handler if the root source file does not -// have a `pub fn panic`. -// If this file wants to import other files *by name*, support for that would -// have to be added in the compiler. - -const builtin = @import("builtin"); -const std = @import("std"); - -pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn { - @setCold(true); - switch (builtin.os) { - .freestanding => { - while (true) { - @breakpoint(); - } - }, - .wasi => { - std.debug.warn("{}", msg); - _ = std.os.wasi.proc_raise(std.os.wasi.SIGABRT); - unreachable; - }, - .uefi => { - // TODO look into using the debug info and logging helpful messages - std.os.abort(); - }, - else => { - const first_trace_addr = @returnAddress(); - std.debug.panicExtra(error_return_trace, first_trace_addr, "{}", msg); - }, - } -} diff --git a/lib/std/std.zig b/lib/std/std.zig index f41181f6e9..ea6257009f 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -22,11 +22,13 @@ pub const SpinLock = @import("spinlock.zig").SpinLock; pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex; pub const StringHashMap = @import("hash_map.zig").StringHashMap; pub const TailQueue = @import("linked_list.zig").TailQueue; +pub const Target = @import("target.zig").Target; pub const Thread = @import("thread.zig").Thread; pub const atomic = @import("atomic.zig"); pub const base64 = @import("base64.zig"); pub const build = @import("build.zig"); +pub const builtin = @import("builtin.zig"); pub const c = @import("c.zig"); pub const coff = @import("coff.zig"); pub const crypto = @import("crypto.zig"); @@ -63,6 +65,6 @@ pub const unicode = @import("unicode.zig"); pub const valgrind = @import("valgrind.zig"); pub const zig = @import("zig.zig"); -comptime { +test "" { meta.refAllDecls(@This()); } diff --git a/lib/std/target.zig b/lib/std/target.zig new file mode 100644 index 0000000000..b81563d327 --- /dev/null +++ b/lib/std/target.zig @@ -0,0 +1,617 @@ +const std = @import("std.zig"); +const builtin = std.builtin; + +/// 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 Os = 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, + zen, + uefi, + }; + + pub const Arch = union(enum) { + arm: Arm32, + armeb: Arm32, + aarch64: Arm64, + aarch64_be: Arm64, + aarch64_32: Arm64, + arc, + avr, + bpfel, + bpfeb, + hexagon, + mips, + mipsel, + mips64, + mips64el, + msp430, + powerpc, + powerpc64, + powerpc64le, + r600, + amdgcn, + riscv32, + riscv64, + sparc, + sparcv9, + sparcel, + s390x, + tce, + tcele, + thumb: Arm32, + thumbeb: Arm32, + i386, + x86_64, + xcore, + nvptx, + nvptx64, + le32, + le64, + amdil, + amdil64, + hsail, + hsail64, + spir, + spir64, + kalimba: Kalimba, + shave, + lanai, + wasm32, + wasm64, + renderscript32, + renderscript64, + + pub const Arm32 = enum { + v8_5a, + v8_4a, + v8_3a, + v8_2a, + v8_1a, + v8, + v8r, + v8m_baseline, + v8m_mainline, + v8_1m_mainline, + v7, + v7em, + v7m, + v7s, + v7k, + v7ve, + v6, + v6m, + v6k, + v6t2, + v5, + v5te, + v4t, + }; + pub const Arm64 = enum { + v8_5a, + v8_4a, + v8_3a, + v8_2a, + v8_1a, + v8, + v8r, + v8m_baseline, + v8m_mainline, + }; + pub const Kalimba = enum { + v5, + v4, + v3, + }; + pub const Mips = enum { + r6, + }; + }; + + pub const Abi = enum { + none, + gnu, + gnuabin32, + gnuabi64, + gnueabi, + gnueabihf, + gnux32, + code16, + eabi, + eabihf, + elfv1, + elfv2, + android, + musl, + musleabi, + musleabihf, + msvc, + itanium, + cygnus, + coreclr, + simulator, + macabi, + }; + + pub const ObjectFormat = enum { + unknown, + coff, + elf, + macho, + wasm, + }; + + pub const SubSystem = enum { + Console, + Windows, + Posix, + Native, + EfiApplication, + EfiBootServiceDriver, + EfiRom, + EfiRuntimeDriver, + }; + + pub const Cross = struct { + arch: Arch, + os: Os, + abi: Abi, + }; + + pub const current = Target{ + .Cross = Cross{ + .arch = builtin.arch, + .os = builtin.os, + .abi = builtin.abi, + }, + }; + + pub fn zigTriple(self: Target, allocator: *std.mem.Allocator) ![]u8 { + return std.fmt.allocPrint( + allocator, + "{}{}-{}-{}", + @tagName(self.getArch()), + Target.archSubArchName(self.getArch()), + @tagName(self.getOs()), + @tagName(self.getAbi()), + ); + } + + pub fn allocDescription(self: Target, allocator: *std.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 zigTripleNoSubArch(self: Target, allocator: *std.mem.Allocator) ![]u8 { + return std.fmt.allocPrint( + allocator, + "{}-{}-{}", + @tagName(self.getArch()), + @tagName(self.getOs()), + @tagName(self.getAbi()), + ); + } + + pub fn linuxTriple(self: Target, allocator: *std.mem.Allocator) ![]u8 { + return std.fmt.allocPrint( + allocator, + "{}-{}-{}", + @tagName(self.getArch()), + @tagName(self.getOs()), + @tagName(self.getAbi()), + ); + } + + pub fn parse(text: []const u8) !Target { + var it = mem.separate(text, "-"); + const arch_name = it.next() orelse return error.MissingArchitecture; + const os_name = it.next() orelse return error.MissingOperatingSystem; + const abi_name = it.next(); + + var cross = Cross{ + .arch = try parseArchSub(arch_name), + .os = try parseOs(os_name), + .abi = undefined, + }; + cross.abi = if (abi_name) |n| try parseAbi(n) else defaultAbi(cross.arch, cross.os); + return Target{ .Cross = cross }; + } + + pub fn defaultAbi(arch: Arch, target_os: Os) Abi { + switch (arch) { + .wasm32, .wasm64 => return .musl, + else => {}, + } + switch (target_os) { + .freestanding, + .ananas, + .cloudabi, + .dragonfly, + .lv2, + .solaris, + .haiku, + .minix, + .rtems, + .nacl, + .cnk, + .aix, + .cuda, + .nvcl, + .amdhsa, + .ps4, + .elfiamcu, + .mesa3d, + .contiki, + .amdpal, + .zen, + .hermit, + => return .eabi, + .openbsd, + .macosx, + .freebsd, + .ios, + .tvos, + .watchos, + .fuchsia, + .kfreebsd, + .netbsd, + .hurd, + => return .gnu, + .windows, + .uefi, + => return .msvc, + .linux, + .wasi, + .emscripten, + => return .musl, + } + } + + pub const ParseArchSubError = error{ + UnknownArchitecture, + UnknownSubArchitecture, + }; + + pub fn parseArchSub(text: []const u8) ParseArchSubError!Arch { + const info = @typeInfo(Arch); + inline for (info.Union.fields) |field| { + if (mem.eql(u8, text, field.name)) { + if (field.field_type == void) { + return (Arch)(@field(Arch, field.name)); + } else { + const sub_info = @typeInfo(field.field_type); + inline for (sub_info.Enum.fields) |sub_field| { + const combined = field.name ++ sub_field.name; + if (mem.eql(u8, text, combined)) { + return @unionInit(Arch, field.name, @field(field.field_type, sub_field.name)); + } + } + return error.UnknownSubArchitecture; + } + } + } + return error.UnknownArchitecture; + } + + pub fn parseOs(text: []const u8) !Os { + const info = @typeInfo(Os); + inline for (info.Enum.fields) |field| { + if (mem.eql(u8, text, field.name)) { + return @field(Os, field.name); + } + } + return error.UnknownOperatingSystem; + } + + pub fn parseAbi(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; + } + + fn archSubArchName(arch: Arch) []const u8 { + return switch (arch) { + .arm => |sub| @tagName(sub), + .armeb => |sub| @tagName(sub), + .thumb => |sub| @tagName(sub), + .thumbeb => |sub| @tagName(sub), + .aarch64 => |sub| @tagName(sub), + .aarch64_be => |sub| @tagName(sub), + .kalimba => |sub| @tagName(sub), + else => "", + }; + } + + pub fn subArchName(self: Target) []const u8 { + switch (self) { + .Native => return archSubArchName(builtin.arch), + .Cross => |cross| return archSubArchName(cross.arch), + } + } + + pub fn oFileExt(self: Target) []const u8 { + return switch (self.getAbi()) { + .msvc => ".obj", + else => ".o", + }; + } + + pub fn exeFileExt(self: Target) []const u8 { + if (self.isWindows()) { + return ".exe"; + } else if (self.isUefi()) { + return ".efi"; + } else if (self.isWasm()) { + return ".wasm"; + } else { + return ""; + } + } + + pub fn staticLibSuffix(self: Target) []const u8 { + if (self.isWasm()) { + return ".wasm"; + } + switch (self.getAbi()) { + .msvc => return ".lib", + else => return ".a", + } + } + + pub fn dynamicLibSuffix(self: Target) []const u8 { + if (self.isDarwin()) { + return ".dylib"; + } + switch (self.getOs()) { + .windows => return ".dll", + else => return ".so", + } + } + + pub fn libPrefix(self: Target) []const u8 { + if (self.isWasm()) { + return ""; + } + switch (self.getAbi()) { + .msvc => return "", + else => return "lib", + } + } + + pub fn getOs(self: Target) Os { + return switch (self) { + .Native => builtin.os, + .Cross => |t| t.os, + }; + } + + pub fn getArch(self: Target) Arch { + switch (self) { + .Native => return builtin.arch, + .Cross => |t| return t.arch, + } + } + + pub fn getAbi(self: Target) Abi { + switch (self) { + .Native => return builtin.abi, + .Cross => |t| return t.abi, + } + } + + pub fn isMinGW(self: Target) bool { + return self.isWindows() and self.isGnu(); + } + + pub fn isGnu(self: Target) bool { + return switch (self.getAbi()) { + .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true, + else => false, + }; + } + + pub fn isDarwin(self: Target) bool { + return switch (self.getOs()) { + .ios, .macosx, .watchos, .tvos => true, + else => false, + }; + } + + pub fn isWindows(self: Target) bool { + return switch (self.getOs()) { + .windows => true, + else => false, + }; + } + + pub fn isLinux(self: Target) bool { + return switch (self.getOs()) { + .linux => true, + else => false, + }; + } + + pub fn isUefi(self: Target) bool { + return switch (self.getOs()) { + .uefi => true, + else => false, + }; + } + + pub fn isWasm(self: Target) bool { + return switch (self.getArch()) { + .wasm32, .wasm64 => true, + else => false, + }; + } + + pub fn isFreeBSD(self: Target) bool { + return switch (self.getOs()) { + .freebsd => true, + else => false, + }; + } + + pub fn isNetBSD(self: Target) bool { + return switch (self.getOs()) { + .netbsd => true, + else => false, + }; + } + + pub fn wantSharedLibSymLinks(self: Target) bool { + return !self.isWindows(); + } + + pub fn osRequiresLibC(self: Target) bool { + return self.isDarwin() or self.isFreeBSD() or self.isNetBSD(); + } + + pub fn getArchPtrBitWidth(self: Target) u32 { + switch (self.getArch()) { + .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, + } + } + + pub const Executor = union(enum) { + native, + qemu: []const u8, + wine: []const u8, + unavailable, + }; + + pub fn getExternalExecutor(self: Target) Executor { + if (@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) { + return switch (self.getArch()) { + .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, + }; + } + + if (self.isWindows()) { + switch (self.getArchPtrBitWidth()) { + 32 => return Executor{ .wine = "wine" }, + 64 => return Executor{ .wine = "wine64" }, + else => return .unavailable, + } + } + + return .unavailable; + } +}; diff --git a/lib/std/thread.zig b/lib/std/thread.zig index 278fcc827c..fbfb1afd1e 100644 --- a/lib/std/thread.zig +++ b/lib/std/thread.zig @@ -9,7 +9,7 @@ const assert = std.debug.assert; pub const Thread = struct { data: Data, - pub const use_pthreads = !windows.is_the_target and builtin.link_libc; + pub const use_pthreads = builtin.os != .windows and builtin.link_libc; /// Represents a kernel thread handle. /// May be an integer or a pointer depending on the platform. @@ -309,7 +309,7 @@ pub const Thread = struct { os.EINVAL => unreachable, else => return os.unexpectedErrno(@intCast(usize, err)), } - } else if (os.linux.is_the_target) { + } else if (builtin.os == .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; @@ -342,18 +342,18 @@ pub const Thread = struct { }; pub fn cpuCount() CpuCountError!usize { - if (os.linux.is_the_target) { + if (builtin.os == .linux) { const cpu_set = try os.sched_getaffinity(0); return usize(os.CPU_COUNT(cpu_set)); // TODO should not need this usize cast } - if (os.windows.is_the_target) { + if (builtin.os == .windows) { var system_info: windows.SYSTEM_INFO = undefined; windows.kernel32.GetSystemInfo(&system_info); return @intCast(usize, system_info.dwNumberOfProcessors); } var count: c_int = undefined; var count_len: usize = @sizeOf(c_int); - const name = if (os.darwin.is_the_target) c"hw.logicalcpu" else c"hw.ncpu"; + const name = if (comptime std.Target.current.isDarwin()) c"hw.logicalcpu" else c"hw.ncpu"; os.sysctlbynameC(name, &count, &count_len, null, 0) catch |err| switch (err) { error.NameTooLong => unreachable, else => |e| return e, diff --git a/lib/std/time.zig b/lib/std/time.zig index caf6c31b31..04dbb908e2 100644 --- a/lib/std/time.zig +++ b/lib/std/time.zig @@ -9,7 +9,7 @@ pub const epoch = @import("time/epoch.zig"); /// Spurious wakeups are possible and no precision of timing is guaranteed. pub fn sleep(nanoseconds: u64) void { - if (os.windows.is_the_target) { + if (builtin.os == .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); @@ -30,7 +30,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 (os.windows.is_the_target) { + if (builtin.os == .windows) { //FileTime has a granularity of 100 nanoseconds // and uses the NTFS/Windows epoch var ft: os.windows.FILETIME = undefined; @@ -41,7 +41,7 @@ pub fn milliTimestamp() u64 { const ft64 = (u64(ft.dwHighDateTime) << 32) | ft.dwLowDateTime; return @divFloor(ft64, hns_per_ms) - -epoch_adj; } - if (os.wasi.is_the_target and !builtin.link_libc) { + if (builtin.os == .wasi and !builtin.link_libc) { var ns: os.wasi.timestamp_t = undefined; // TODO: Verify that precision is ignored @@ -51,7 +51,7 @@ pub fn milliTimestamp() u64 { const ns_per_ms = 1000; return @divFloor(ns, ns_per_ms); } - if (os.darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { var tv: os.darwin.timeval = undefined; var err = os.darwin.gettimeofday(&tv, null); assert(err == 0); @@ -126,11 +126,11 @@ pub const Timer = struct { pub fn start() Error!Timer { var self: Timer = undefined; - if (os.windows.is_the_target) { + if (builtin.os == .windows) { self.frequency = os.windows.QueryPerformanceFrequency(); self.resolution = @divFloor(ns_per_s, self.frequency); self.start_time = os.windows.QueryPerformanceCounter(); - } else if (os.darwin.is_the_target) { + } else if (comptime std.Target.current.isDarwin()) { os.darwin.mach_timebase_info(&self.frequency); self.resolution = @divFloor(self.frequency.numer, self.frequency.denom); self.start_time = os.darwin.mach_absolute_time(); @@ -154,10 +154,10 @@ pub const Timer = struct { /// Reads the timer value since start or the last reset in nanoseconds pub fn read(self: *Timer) u64 { var clock = clockNative() - self.start_time; - if (os.windows.is_the_target) { + if (builtin.os == .windows) { return @divFloor(clock * ns_per_s, self.frequency); } - if (os.darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { return @divFloor(clock * self.frequency.numer, self.frequency.denom); } return clock; @@ -177,10 +177,10 @@ pub const Timer = struct { } fn clockNative() u64 { - if (os.windows.is_the_target) { + if (builtin.os == .windows) { return os.windows.QueryPerformanceCounter(); } - if (os.darwin.is_the_target) { + if (comptime std.Target.current.isDarwin()) { return os.darwin.mach_absolute_time(); } var ts: os.timespec = undefined; diff --git a/src-self-hosted/target.zig b/src-self-hosted/target.zig index 15f09e8da9..c62e5af9dd 100644 --- a/src-self-hosted/target.zig +++ b/src-self-hosted/target.zig @@ -3,6 +3,8 @@ const builtin = @import("builtin"); const llvm = @import("llvm.zig"); const CInt = @import("c_int.zig").CInt; +// TODO delete this file and use std.Target + pub const FloatAbi = enum { Hard, Soft, diff --git a/src/all_types.hpp b/src/all_types.hpp index 052c67d334..a8cfa0227f 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1930,7 +1930,6 @@ struct CodeGen { ZigList type_resolve_stack; ZigPackage *std_package; - ZigPackage *panic_package; ZigPackage *test_runner_package; ZigPackage *compile_var_package; ZigType *compile_var_import; @@ -2006,7 +2005,6 @@ struct CodeGen { ZigFn *cur_fn; ZigFn *main_fn; ZigFn *panic_fn; - TldFn *panic_tld_fn; ZigFn *largest_frame_fn; @@ -2030,7 +2028,6 @@ struct CodeGen { bool have_winmain; bool have_winmain_crt_startup; bool have_dllmain_crt_startup; - bool have_pub_panic; bool have_err_ret_tracing; bool c_want_stdint; bool c_want_stdbool; diff --git a/src/analyze.cpp b/src/analyze.cpp index 44223b58b4..e2df290df6 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3232,21 +3232,6 @@ static bool scope_is_root_decls(Scope *scope) { zig_unreachable(); } -void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn) { - ConstExprValue *panic_fn_type_val = get_builtin_value(g, "PanicFn"); - assert(panic_fn_type_val != nullptr); - assert(panic_fn_type_val->type->id == ZigTypeIdMetaType); - ZigType *panic_fn_type = panic_fn_type_val->data.x_type; - - AstNode *fake_decl = allocate(1); - *fake_decl = *panic_fn->proto_node; - fake_decl->type = NodeTypeSymbol; - fake_decl->data.symbol_expr.symbol = tld_fn->base.name; - - // call this for the side effects of casting to panic_fn_type - analyze_const_value(g, tld_fn->base.parent_scope, fake_decl, panic_fn_type, nullptr, UndefBad); -} - ZigType *get_test_fn_type(CodeGen *g) { if (g->test_fn_type) return g->test_fn_type; @@ -3356,16 +3341,9 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { fn_table_entry->inferred_async_node = fn_table_entry->proto_node; } - if (scope_is_root_decls(tld_fn->base.parent_scope) && - (import == g->root_import || import->data.structure.root_struct->package == g->panic_package)) - { + if (scope_is_root_decls(tld_fn->base.parent_scope) && import == g->root_import) { if (g->have_pub_main && buf_eql_str(tld_fn->base.name, "main")) { g->main_fn = fn_table_entry; - } else if ((import->data.structure.root_struct->package == g->panic_package || g->have_pub_panic) && - buf_eql_str(tld_fn->base.name, "panic")) - { - g->panic_fn = fn_table_entry; - g->panic_tld_fn = tld_fn; } } } else if (source_node->type == NodeTypeTestDecl) { @@ -4710,8 +4688,8 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Bu ast_print(stderr, root_node, 0); } - if (source_kind == SourceKindRoot || package == g->panic_package) { - // Look for panic and main + if (source_kind == SourceKindRoot) { + // Look for main for (size_t decl_i = 0; decl_i < root_node->data.container_decl.decls.length; decl_i += 1) { AstNode *top_level_decl = root_node->data.container_decl.decls.at(decl_i); @@ -4724,8 +4702,6 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Bu if (is_pub) { if (buf_eql_str(proto_name, "main")) { g->have_pub_main = true; - } else if (buf_eql_str(proto_name, "panic")) { - g->have_pub_panic = true; } } } @@ -8932,3 +8908,62 @@ IrInstruction *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node, return &alloca_gen->base; } +Error analyze_import(CodeGen *g, ZigType *source_import, Buf *import_target_str, + ZigType **out_import, Buf **out_import_target_path, Buf *out_full_path) +{ + Error err; + + Buf *search_dir; + ZigPackage *cur_scope_pkg = source_import->data.structure.root_struct->package; + assert(cur_scope_pkg); + ZigPackage *target_package; + auto package_entry = cur_scope_pkg->package_table.maybe_get(import_target_str); + SourceKind source_kind; + if (package_entry) { + target_package = package_entry->value; + *out_import_target_path = &target_package->root_src_path; + search_dir = &target_package->root_src_dir; + source_kind = SourceKindPkgMain; + } else { + // try it as a filename + target_package = cur_scope_pkg; + *out_import_target_path = import_target_str; + + // search relative to importing file + search_dir = buf_alloc(); + os_path_dirname(source_import->data.structure.root_struct->path, search_dir); + + source_kind = SourceKindNonRoot; + } + + buf_resize(out_full_path, 0); + os_path_join(search_dir, *out_import_target_path, out_full_path); + + Buf *import_code = buf_alloc(); + Buf *resolved_path = buf_alloc(); + + Buf *resolve_paths[] = { out_full_path, }; + *resolved_path = os_path_resolve(resolve_paths, 1); + + auto import_entry = g->import_table.maybe_get(resolved_path); + if (import_entry) { + *out_import = import_entry->value; + return ErrorNone; + } + + if (source_kind == SourceKindNonRoot) { + Buf *pkg_root_src_dir = &cur_scope_pkg->root_src_dir; + Buf resolved_root_src_dir = os_path_resolve(&pkg_root_src_dir, 1); + if (!buf_starts_with_buf(resolved_path, &resolved_root_src_dir)) { + return ErrorImportOutsidePkgPath; + } + } + + if ((err = file_fetch(g, resolved_path, import_code))) { + return err; + } + + *out_import = add_source_file(g, target_package, resolved_path, import_code, source_kind); + return ErrorNone; +} + diff --git a/src/analyze.hpp b/src/analyze.hpp index 4592d1a0a1..5168dd2d7d 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -262,5 +262,7 @@ void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn); IrInstruction *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node, ZigFn *fn, ZigType *var_type, const char *name_hint); +Error analyze_import(CodeGen *codegen, ZigType *source_import, Buf *import_target_str, + ZigType **out_import, Buf **out_import_target_path, Buf *out_full_path); #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index 1b14c5551b..87cdcc8783 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8125,55 +8125,37 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { g->have_err_ret_tracing = detect_err_ret_tracing(g); Buf *contents = buf_alloc(); - - // NOTE: when editing this file, you may need to make modifications to the - // cache input parameters in define_builtin_compile_vars - - // Modifications to this struct must be coordinated with code that does anything with - // g->stack_trace_type. There are hard-coded references to the field indexes. - buf_append_str(contents, - "pub const StackTrace = struct {\n" - " index: usize,\n" - " instruction_addresses: []usize,\n" - "};\n\n"); - - buf_append_str(contents, "pub const PanicFn = fn([]const u8, ?*StackTrace) noreturn;\n\n"); + buf_appendf(contents, "usingnamespace @import(\"std\").builtin;\n\n"); const char *cur_os = nullptr; { - buf_appendf(contents, "pub const Os = enum {\n"); uint32_t field_count = (uint32_t)target_os_count(); for (uint32_t i = 0; i < field_count; i += 1) { Os os_type = target_os_enum(i); const char *name = target_os_name(os_type); - buf_appendf(contents, " %s,\n", name); if (os_type == g->zig_target->os) { g->target_os_index = i; cur_os = name; } } - buf_appendf(contents, "};\n\n"); } assert(cur_os != nullptr); const char *cur_arch = nullptr; { - buf_appendf(contents, "pub const Arch = union(enum) {\n"); uint32_t field_count = (uint32_t)target_arch_count(); for (uint32_t arch_i = 0; arch_i < field_count; arch_i += 1) { ZigLLVM_ArchType arch = target_arch_enum(arch_i); const char *arch_name = target_arch_name(arch); SubArchList sub_arch_list = target_subarch_list(arch); if (sub_arch_list == SubArchListNone) { - buf_appendf(contents, " %s,\n", arch_name); if (arch == g->zig_target->arch) { g->target_arch_index = arch_i; cur_arch = buf_ptr(buf_sprintf("Arch.%s", arch_name)); } } else { const char *sub_arch_list_name = target_subarch_list_name(sub_arch_list); - buf_appendf(contents, " %s: %s,\n", arch_name, sub_arch_list_name); if (arch == g->zig_target->arch) { size_t sub_count = target_subarch_count(sub_arch_list); for (size_t sub_i = 0; sub_i < sub_count; sub_i += 1) { @@ -8187,50 +8169,30 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { } } } - - uint32_t list_count = target_subarch_list_count(); - // start at index 1 to skip None - for (uint32_t list_i = 1; list_i < list_count; list_i += 1) { - SubArchList sub_arch_list = target_subarch_list_enum(list_i); - const char *subarch_list_name = target_subarch_list_name(sub_arch_list); - buf_appendf(contents, " pub const %s = enum {\n", subarch_list_name); - size_t sub_count = target_subarch_count(sub_arch_list); - for (size_t sub_i = 0; sub_i < sub_count; sub_i += 1) { - ZigLLVM_SubArchType sub = target_subarch_enum(sub_arch_list, sub_i); - buf_appendf(contents, " %s,\n", target_subarch_name(sub)); - } - buf_appendf(contents, " };\n"); - } - buf_appendf(contents, "};\n\n"); } assert(cur_arch != nullptr); const char *cur_abi = nullptr; { - buf_appendf(contents, "pub const Abi = enum {\n"); uint32_t field_count = (uint32_t)target_abi_count(); for (uint32_t i = 0; i < field_count; i += 1) { ZigLLVM_EnvironmentType abi = target_abi_enum(i); const char *name = target_abi_name(abi); - buf_appendf(contents, " %s,\n", name); if (abi == g->zig_target->abi) { g->target_abi_index = i; cur_abi = name; } } - buf_appendf(contents, "};\n\n"); } assert(cur_abi != nullptr); const char *cur_obj_fmt = nullptr; { - buf_appendf(contents, "pub const ObjectFormat = enum {\n"); uint32_t field_count = (uint32_t)target_oformat_count(); for (uint32_t i = 0; i < field_count; i += 1) { ZigLLVM_ObjectFormatType oformat = target_oformat_enum(i); const char *name = target_oformat_name(oformat); - buf_appendf(contents, " %s,\n", name); ZigLLVM_ObjectFormatType target_oformat = target_object_format(g->zig_target); if (oformat == target_oformat) { @@ -8239,311 +8201,39 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { } } - buf_appendf(contents, "};\n\n"); } assert(cur_obj_fmt != nullptr); - { - buf_appendf(contents, "pub const GlobalLinkage = enum {\n"); - uint32_t field_count = array_length(global_linkage_values); - for (uint32_t i = 0; i < field_count; i += 1) { - const GlobalLinkageValue *value = &global_linkage_values[i]; - buf_appendf(contents, " %s,\n", value->name); - } - buf_appendf(contents, "};\n\n"); - } - { - buf_appendf(contents, - "pub const AtomicOrder = enum {\n" - " Unordered,\n" - " Monotonic,\n" - " Acquire,\n" - " Release,\n" - " AcqRel,\n" - " SeqCst,\n" - "};\n\n"); - } - { - buf_appendf(contents, - "pub const AtomicRmwOp = enum {\n" - " Xchg,\n" - " Add,\n" - " Sub,\n" - " And,\n" - " Nand,\n" - " Or,\n" - " Xor,\n" - " Max,\n" - " Min,\n" - "};\n\n"); - } - { - buf_appendf(contents, - "pub const Mode = enum {\n" - " Debug,\n" - " ReleaseSafe,\n" - " ReleaseFast,\n" - " ReleaseSmall,\n" - "};\n\n"); - } - { - buf_appendf(contents, "pub const TypeId = enum {\n"); - size_t field_count = type_id_len(); - for (size_t i = 0; i < field_count; i += 1) { - const ZigTypeId id = type_id_at_index(i); - buf_appendf(contents, " %s,\n", type_id_name(id)); - } - buf_appendf(contents, "};\n\n"); - } - { - buf_appendf(contents, - "pub const TypeInfo = union(TypeId) {\n" - " Type: void,\n" - " Void: void,\n" - " Bool: void,\n" - " NoReturn: void,\n" - " Int: Int,\n" - " Float: Float,\n" - " Pointer: Pointer,\n" - " Array: Array,\n" - " Struct: Struct,\n" - " ComptimeFloat: void,\n" - " ComptimeInt: void,\n" - " Undefined: void,\n" - " Null: void,\n" - " Optional: Optional,\n" - " ErrorUnion: ErrorUnion,\n" - " ErrorSet: ErrorSet,\n" - " Enum: Enum,\n" - " Union: Union,\n" - " Fn: Fn,\n" - " BoundFn: Fn,\n" - " ArgTuple: void,\n" - " Opaque: void,\n" - " Frame: void,\n" - " AnyFrame: AnyFrame,\n" - " Vector: Vector,\n" - " EnumLiteral: void,\n" - "\n\n" - " pub const Int = struct {\n" - " is_signed: bool,\n" - " bits: comptime_int,\n" - " };\n" - "\n" - " pub const Float = struct {\n" - " bits: comptime_int,\n" - " };\n" - "\n" - " pub const Pointer = struct {\n" - " size: Size,\n" - " is_const: bool,\n" - " is_volatile: bool,\n" - " alignment: comptime_int,\n" - " child: type,\n" - " is_allowzero: bool,\n" - "\n" - " pub const Size = enum {\n" - " One,\n" - " Many,\n" - " Slice,\n" - " C,\n" - " };\n" - " };\n" - "\n" - " pub const Array = struct {\n" - " len: comptime_int,\n" - " child: type,\n" - " };\n" - "\n" - " pub const ContainerLayout = enum {\n" - " Auto,\n" - " Extern,\n" - " Packed,\n" - " };\n" - "\n" - " pub const StructField = struct {\n" - " name: []const u8,\n" - " offset: ?comptime_int,\n" - " field_type: type,\n" - " };\n" - "\n" - " pub const Struct = struct {\n" - " layout: ContainerLayout,\n" - " fields: []StructField,\n" - " decls: []Declaration,\n" - " };\n" - "\n" - " pub const Optional = struct {\n" - " child: type,\n" - " };\n" - "\n" - " pub const ErrorUnion = struct {\n" - " error_set: type,\n" - " payload: type,\n" - " };\n" - "\n" - " pub const Error = struct {\n" - " name: []const u8,\n" - " value: comptime_int,\n" - " };\n" - "\n" - " pub const ErrorSet = ?[]Error;\n" - "\n" - " pub const EnumField = struct {\n" - " name: []const u8,\n" - " value: comptime_int,\n" - " };\n" - "\n" - " pub const Enum = struct {\n" - " layout: ContainerLayout,\n" - " tag_type: type,\n" - " fields: []EnumField,\n" - " decls: []Declaration,\n" - " };\n" - "\n" - " pub const UnionField = struct {\n" - " name: []const u8,\n" - " enum_field: ?EnumField,\n" - " field_type: type,\n" - " };\n" - "\n" - " pub const Union = struct {\n" - " layout: ContainerLayout,\n" - " tag_type: ?type,\n" - " fields: []UnionField,\n" - " decls: []Declaration,\n" - " };\n" - "\n" - " pub const CallingConvention = enum {\n" - " Unspecified,\n" - " C,\n" - " Cold,\n" - " Naked,\n" - " Stdcall,\n" - " Async,\n" - " };\n" - "\n" - " pub const FnArg = struct {\n" - " is_generic: bool,\n" - " is_noalias: bool,\n" - " arg_type: ?type,\n" - " };\n" - "\n" - " pub const Fn = struct {\n" - " calling_convention: CallingConvention,\n" - " is_generic: bool,\n" - " is_var_args: bool,\n" - " return_type: ?type,\n" - " args: []FnArg,\n" - " };\n" - "\n" - " pub const AnyFrame = struct {\n" - " child: ?type,\n" - " };\n" - "\n" - " pub const Vector = struct {\n" - " len: comptime_int,\n" - " child: type,\n" - " };\n" - "\n" - " pub const Declaration = struct {\n" - " name: []const u8,\n" - " is_pub: bool,\n" - " data: Data,\n" - "\n" - " pub const Data = union(enum) {\n" - " Type: type,\n" - " Var: type,\n" - " Fn: FnDecl,\n" - "\n" - " pub const FnDecl = struct {\n" - " fn_type: type,\n" - " inline_type: Inline,\n" - " calling_convention: CallingConvention,\n" - " is_var_args: bool,\n" - " is_extern: bool,\n" - " is_export: bool,\n" - " lib_name: ?[]const u8,\n" - " return_type: type,\n" - " arg_names: [][] const u8,\n" - "\n" - " pub const Inline = enum {\n" - " Auto,\n" - " Always,\n" - " Never,\n" - " };\n" - " };\n" - " };\n" - " };\n" - "};\n\n"); - static_assert(ContainerLayoutAuto == 0, ""); - static_assert(ContainerLayoutExtern == 1, ""); - static_assert(ContainerLayoutPacked == 2, ""); + // If any of these asserts trip then you need to either fix the internal compiler enum + // or the corresponding one in std.Target or std.builtin. + static_assert(ContainerLayoutAuto == 0, ""); + static_assert(ContainerLayoutExtern == 1, ""); + static_assert(ContainerLayoutPacked == 2, ""); - static_assert(CallingConventionUnspecified == 0, ""); - static_assert(CallingConventionC == 1, ""); - static_assert(CallingConventionCold == 2, ""); - static_assert(CallingConventionNaked == 3, ""); - static_assert(CallingConventionStdcall == 4, ""); - static_assert(CallingConventionAsync == 5, ""); + static_assert(CallingConventionUnspecified == 0, ""); + static_assert(CallingConventionC == 1, ""); + static_assert(CallingConventionCold == 2, ""); + static_assert(CallingConventionNaked == 3, ""); + static_assert(CallingConventionStdcall == 4, ""); + static_assert(CallingConventionAsync == 5, ""); - static_assert(FnInlineAuto == 0, ""); - static_assert(FnInlineAlways == 1, ""); - static_assert(FnInlineNever == 2, ""); + static_assert(FnInlineAuto == 0, ""); + static_assert(FnInlineAlways == 1, ""); + static_assert(FnInlineNever == 2, ""); - static_assert(BuiltinPtrSizeOne == 0, ""); - static_assert(BuiltinPtrSizeMany == 1, ""); - static_assert(BuiltinPtrSizeSlice == 2, ""); - static_assert(BuiltinPtrSizeC == 3, ""); - } - { - buf_appendf(contents, - "pub const FloatMode = enum {\n" - " Strict,\n" - " Optimized,\n" - "};\n\n"); - assert(FloatModeStrict == 0); - assert(FloatModeOptimized == 1); - } - { - buf_appendf(contents, - "pub const Endian = enum {\n" - " Big,\n" - " Little,\n" - "};\n\n"); - //assert(EndianBig == 0); - //assert(EndianLittle == 1); - } - { - buf_appendf(contents, - "pub const Version = struct {\n" - " major: u32,\n" - " minor: u32,\n" - " patch: u32,\n" - "};\n\n"); - } - { - buf_appendf(contents, - "pub const SubSystem = enum {\n" - " Console,\n" - " Windows,\n" - " Posix,\n" - " Native,\n" - " EfiApplication,\n" - " EfiBootServiceDriver,\n" - " EfiRom,\n" - " EfiRuntimeDriver,\n" - "};\n\n"); + static_assert(BuiltinPtrSizeOne == 0, ""); + static_assert(BuiltinPtrSizeMany == 1, ""); + static_assert(BuiltinPtrSizeSlice == 2, ""); + static_assert(BuiltinPtrSizeC == 3, ""); - assert(TargetSubsystemConsole == 0); - assert(TargetSubsystemWindows == 1); - assert(TargetSubsystemPosix == 2); - assert(TargetSubsystemNative == 3); - assert(TargetSubsystemEfiApplication == 4); - assert(TargetSubsystemEfiBootServiceDriver == 5); - assert(TargetSubsystemEfiRom == 6); - assert(TargetSubsystemEfiRuntimeDriver == 7); - } + static_assert(TargetSubsystemConsole == 0, ""); + static_assert(TargetSubsystemWindows == 1, ""); + static_assert(TargetSubsystemPosix == 2, ""); + static_assert(TargetSubsystemNative == 3, ""); + static_assert(TargetSubsystemEfiApplication == 4, ""); + static_assert(TargetSubsystemEfiBootServiceDriver == 5, ""); + static_assert(TargetSubsystemEfiRom == 6, ""); + static_assert(TargetSubsystemEfiRuntimeDriver == 7, ""); { const char *endian_str = g->is_big_endian ? "Endian.Big" : "Endian.Little"; buf_appendf(contents, "pub const endian = %s;\n", endian_str); @@ -8573,7 +8263,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { { TargetSubsystem detected_subsystem = detect_subsystem(g); if (detected_subsystem != TargetSubsystemAuto) { - buf_appendf(contents, "pub const subsystem = SubSystem.%s;\n", subsystem_to_str(detected_subsystem)); + buf_appendf(contents, "pub const explicit_subsystem = SubSystem.%s;\n", subsystem_to_str(detected_subsystem)); } } @@ -8594,10 +8284,6 @@ static ZigPackage *create_test_runner_pkg(CodeGen *g) { return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "test_runner.zig", "std.special"); } -static ZigPackage *create_panic_pkg(CodeGen *g) { - return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "panic.zig", "std.special"); -} - static Error define_builtin_compile_vars(CodeGen *g) { if (g->std_package == nullptr) return ErrorNone; @@ -8679,6 +8365,7 @@ static Error define_builtin_compile_vars(CodeGen *g) { assert(g->root_package); assert(g->std_package); g->compile_var_package = new_package(buf_ptr(this_dir), builtin_zig_basename, "builtin"); + g->compile_var_package->package_table.put(buf_create_from_str("std"), g->std_package); g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); g->std_package->package_table.put(buf_create_from_str("std"), g->std_package); @@ -9377,16 +9064,43 @@ static void gen_root_source(CodeGen *g) { if (!g->is_dummy_so) { // Zig has lazy top level definitions. Here we semantically analyze the panic function. - ZigType *import_with_panic; - if (g->have_pub_panic) { - import_with_panic = g->root_import; - } else { - g->panic_package = create_panic_pkg(g); - import_with_panic = add_special_code(g, g->panic_package, "panic.zig"); + Buf *import_target_path; + Buf full_path = BUF_INIT; + ZigType *std_import; + if ((err = analyze_import(g, g->root_import, buf_create_from_str("std"), &std_import, + &import_target_path, &full_path))) + { + if (err == ErrorFileNotFound) { + fprintf(stderr, "unable to find '%s'", buf_ptr(import_target_path)); + } else { + fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(&full_path), err_str(err)); + } + exit(1); } - Tld *panic_tld = find_decl(g, &get_container_scope(import_with_panic)->base, buf_create_from_str("panic")); + + Tld *builtin_tld = find_decl(g, &get_container_scope(std_import)->base, + buf_create_from_str("builtin")); + assert(builtin_tld != nullptr); + resolve_top_level_decl(g, builtin_tld, nullptr, false); + report_errors_and_maybe_exit(g); + assert(builtin_tld->id == TldIdVar); + TldVar *builtin_tld_var = (TldVar*)builtin_tld; + ConstExprValue *builtin_val = builtin_tld_var->var->const_value; + assert(builtin_val->type->id == ZigTypeIdMetaType); + ZigType *builtin_type = builtin_val->data.x_type; + + Tld *panic_tld = find_decl(g, &get_container_scope(builtin_type)->base, + buf_create_from_str("panic")); assert(panic_tld != nullptr); resolve_top_level_decl(g, panic_tld, nullptr, false); + report_errors_and_maybe_exit(g); + assert(panic_tld->id == TldIdVar); + TldVar *panic_tld_var = (TldVar*)panic_tld; + ConstExprValue *panic_fn_val = panic_tld_var->var->const_value; + assert(panic_fn_val->type->id == ZigTypeIdFn); + assert(panic_fn_val->data.x_ptr.special == ConstPtrSpecialFunction); + g->panic_fn = panic_fn_val->data.x_ptr.data.fn.fn_entry; + assert(g->panic_fn != nullptr); } @@ -9416,10 +9130,6 @@ static void gen_root_source(CodeGen *g) { } } - if (!g->is_dummy_so) { - typecheck_panic_fn(g, g->panic_tld_fn, g->panic_fn); - } - report_errors_and_maybe_exit(g); } diff --git a/src/error.cpp b/src/error.cpp index 86df76ed4e..9fc0383b1b 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -57,6 +57,7 @@ const char *err_str(Error err) { case ErrorNoCCompilerInstalled: return "no C compiler installed"; case ErrorNotLazy: return "not lazy"; case ErrorIsAsync: return "is async"; + case ErrorImportOutsidePkgPath: return "import of file outside package path"; } return "(invalid error)"; } diff --git a/src/ir.cpp b/src/ir.cpp index 4cce464a4c..8aff5e4583 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -19589,57 +19589,18 @@ static IrInstruction *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructio AstNode *source_node = import_instruction->base.source_node; ZigType *import = source_node->owner; + ZigType *target_import; Buf *import_target_path; - Buf *search_dir; - assert(import->data.structure.root_struct->package); - ZigPackage *target_package; - auto package_entry = import->data.structure.root_struct->package->package_table.maybe_get(import_target_str); - SourceKind source_kind; - if (package_entry) { - target_package = package_entry->value; - import_target_path = &target_package->root_src_path; - search_dir = &target_package->root_src_dir; - source_kind = SourceKindPkgMain; - } else { - // try it as a filename - target_package = import->data.structure.root_struct->package; - import_target_path = import_target_str; - - // search relative to importing file - search_dir = buf_alloc(); - os_path_dirname(import->data.structure.root_struct->path, search_dir); - - source_kind = SourceKindNonRoot; - } - Buf full_path = BUF_INIT; - os_path_join(search_dir, import_target_path, &full_path); - - Buf *import_code = buf_alloc(); - Buf *resolved_path = buf_alloc(); - - Buf *resolve_paths[] = { &full_path, }; - *resolved_path = os_path_resolve(resolve_paths, 1); - - auto import_entry = ira->codegen->import_table.maybe_get(resolved_path); - if (import_entry) { - return ir_const_type(ira, &import_instruction->base, import_entry->value); - } - - if (source_kind == SourceKindNonRoot) { - ZigPackage *cur_scope_pkg = scope_package(import_instruction->base.scope); - Buf *pkg_root_src_dir = &cur_scope_pkg->root_src_dir; - Buf resolved_root_src_dir = os_path_resolve(&pkg_root_src_dir, 1); - if (!buf_starts_with_buf(resolved_path, &resolved_root_src_dir)) { + if ((err = analyze_import(ira->codegen, import, import_target_str, &target_import, + &import_target_path, &full_path))) + { + if (err == ErrorImportOutsidePkgPath) { ir_add_error_node(ira, source_node, buf_sprintf("import of file outside package path: '%s'", buf_ptr(import_target_path))); return ira->codegen->invalid_instruction; - } - } - - if ((err = file_fetch(ira->codegen, resolved_path, import_code))) { - if (err == ErrorFileNotFound) { + } else if (err == ErrorFileNotFound) { ir_add_error_node(ira, source_node, buf_sprintf("unable to find '%s'", buf_ptr(import_target_path))); return ira->codegen->invalid_instruction; @@ -19650,8 +19611,6 @@ static IrInstruction *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructio } } - ZigType *target_import = add_source_file(ira->codegen, target_package, resolved_path, import_code, source_kind); - return ir_const_type(ira, &import_instruction->base, target_import); } diff --git a/src/userland.h b/src/userland.h index 58d5cc719a..1d01257175 100644 --- a/src/userland.h +++ b/src/userland.h @@ -77,6 +77,7 @@ enum Error { ErrorNoSpaceLeft, ErrorNotLazy, ErrorIsAsync, + ErrorImportOutsidePkgPath, }; // ABI warning diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 35c6ded4a4..c7b0e09485 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -64,7 +64,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = @Type(0); \\} , - "tmp.zig:2:15: error: expected type 'builtin.TypeInfo', found 'comptime_int'", + "tmp.zig:2:15: error: expected type 'std.builtin.TypeInfo', found 'comptime_int'", ); cases.add( @@ -88,7 +88,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ }); \\} , - "tmp.zig:3:36: error: expected type 'builtin.TypeInfo', found 'builtin.Int'", + "tmp.zig:3:36: error: expected type 'std.builtin.TypeInfo', found 'std.builtin.Int'", ); cases.add( @@ -806,7 +806,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\pub fn panic() void {} \\ , - "tmp.zig:3:5: error: expected type 'fn([]const u8, ?*builtin.StackTrace) noreturn', found 'fn() void'", + "error: expected type 'fn([]const u8, ?*std.builtin.StackTrace) noreturn', found 'fn() void'", ); cases.add( @@ -815,8 +815,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ while (true) {} \\} , - "tmp.zig:1:5: error: expected type 'fn([]const u8, ?*builtin.StackTrace) noreturn', found 'fn([]const u8,var)var'", - "tmp.zig:1:5: note: only one of the functions is generic", + "error: expected type 'fn([]const u8, ?*std.builtin.StackTrace) noreturn', found 'fn([]const u8,var)var'", + "note: only one of the functions is generic", ); cases.add( @@ -1473,7 +1473,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ const field = @typeInfo(Struct).Struct.fields[index]; \\} , - "tmp.zig:9:51: error: values of type 'builtin.StructField' must be comptime known, but index value is runtime known", + "tmp.zig:9:51: error: values of type 'std.builtin.StructField' must be comptime known, but index value is runtime known", ); cases.add( @@ -3743,13 +3743,19 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ); cases.add( - "missing function name and param name", + "missing function name", \\fn () void {} - \\fn f(i32) void {} \\export fn entry() usize { return @sizeOf(@typeOf(f)); } , "tmp.zig:1:1: error: missing function name", - "tmp.zig:2:6: error: missing parameter name", + ); + + cases.add( + "missing param name", + \\fn f(i32) void {} + \\export fn entry() usize { return @sizeOf(@typeOf(f)); } + , + "tmp.zig:1:6: error: missing parameter name", ); cases.add( @@ -3782,7 +3788,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn entry() usize { return @sizeOf(@typeOf(func)); } , "tmp.zig:2:1: error: redefinition of 'func'", - "tmp.zig:1:11: error: use of undeclared identifier 'bogus'", ); cases.add( @@ -5086,7 +5091,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ const foo = builtin.Arch.x86; \\} , - "tmp.zig:3:29: error: container 'builtin.Arch' has no member called 'x86'", + "tmp.zig:3:29: error: container 'std.target.Arch' has no member called 'x86'", ); cases.add( @@ -5731,7 +5736,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, u32(1234), u32(1234))) {} \\} , - "tmp.zig:3:50: error: expected type 'builtin.AtomicOrder', found 'u32'", + "tmp.zig:3:50: error: expected type 'std.builtin.AtomicOrder', found 'u32'", ); cases.add( @@ -5741,7 +5746,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ @export("entry", entry, u32(1234)); \\} , - "tmp.zig:3:32: error: expected type 'builtin.GlobalLinkage', found 'u32'", + "tmp.zig:3:32: error: expected type 'std.builtin.GlobalLinkage', found 'u32'", ); cases.add(