diff options
| -rw-r--r-- | lib/std/crypto/tlcsprng.zig | 21 | ||||
| -rw-r--r-- | lib/std/debug.zig | 7 | ||||
| -rw-r--r-- | lib/std/event/batch.zig | 2 | ||||
| -rw-r--r-- | lib/std/event/loop.zig | 23 | ||||
| -rw-r--r-- | lib/std/fs.zig | 12 | ||||
| -rw-r--r-- | lib/std/fs/file.zig | 2 | ||||
| -rw-r--r-- | lib/std/io.zig | 9 | ||||
| -rw-r--r-- | lib/std/log.zig | 41 | ||||
| -rw-r--r-- | lib/std/start.zig | 4 | ||||
| -rw-r--r-- | lib/std/std.zig | 69 | ||||
| -rw-r--r-- | lib/test_runner.zig | 7 | ||||
| -rw-r--r-- | src/crash_report.zig | 8 | ||||
| -rw-r--r-- | src/main.zig | 26 | ||||
| -rw-r--r-- | test/behavior/pointers.zig | 4 | ||||
| -rw-r--r-- | test/compare_output.zig | 18 | ||||
| -rw-r--r-- | test/standalone/issue_7030/main.zig | 4 | ||||
| -rw-r--r-- | test/standalone/issue_9693/main.zig | 4 |
17 files changed, 164 insertions, 97 deletions
diff --git a/lib/std/crypto/tlcsprng.zig b/lib/std/crypto/tlcsprng.zig index 4d75e8c9c7..5a09e20f07 100644 --- a/lib/std/crypto/tlcsprng.zig +++ b/lib/std/crypto/tlcsprng.zig @@ -5,7 +5,6 @@ const std = @import("std"); const builtin = @import("builtin"); -const root = @import("root"); const mem = std.mem; const os = std.os; @@ -67,8 +66,8 @@ fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void { // Allow applications to decide they would prefer to have every call to // std.crypto.random always make an OS syscall, rather than rely on an // application implementation of a CSPRNG. - if (comptime std.meta.globalOption("crypto_always_getrandom", bool) orelse false) { - return fillWithOsEntropy(buffer); + if (std.options.crypto_always_getrandom) { + return defaultRandomSeed(buffer); } if (wipe_mem.len == 0) { @@ -86,7 +85,7 @@ fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void { ) catch { // Could not allocate memory for the local state, fall back to // the OS syscall. - return fillWithOsEntropy(buffer); + return std.options.cryptoRandomSeed(buffer); }; // The memory is already zero-initialized. } else { @@ -128,14 +127,14 @@ fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void { // Since we failed to set up fork safety, we fall back to always // calling getrandom every time. ctx.init_state = .failed; - return fillWithOsEntropy(buffer); + return std.options.cryptoRandomSeed(buffer); }, .initialized => { return fillWithCsprng(buffer); }, .failed => { if (want_fork_safety) { - return fillWithOsEntropy(buffer); + return std.options.cryptoRandomSeed(buffer); } else { unreachable; } @@ -165,7 +164,7 @@ fn fillWithCsprng(buffer: []u8) void { mem.set(u8, ctx.gimli.toSlice()[0..std.crypto.core.Gimli.RATE], 0); } -fn fillWithOsEntropy(buffer: []u8) void { +pub fn defaultRandomSeed(buffer: []u8) void { os.getrandom(buffer) catch @panic("getrandom() failed to provide entropy"); } @@ -174,12 +173,8 @@ fn initAndFill(buffer: []u8) void { // Because we panic on getrandom() failing, we provide the opportunity // to override the default seed function. This also makes // `std.crypto.random` available on freestanding targets, provided that - // the `cryptoRandomSeed` function is provided. - if (@hasDecl(root, "cryptoRandomSeed")) { - root.cryptoRandomSeed(&seed); - } else { - fillWithOsEntropy(&seed); - } + // the `std.options.cryptoRandomSeed` function is provided. + std.options.cryptoRandomSeed(&seed); const ctx = @ptrCast(*Context, wipe_mem.ptr); ctx.gimli = std.crypto.core.Gimli.init(seed); diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 933af55cc9..44310de261 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -1861,10 +1861,9 @@ pub const have_segfault_handling_support = switch (native_os) { .freebsd, .openbsd => @hasDecl(os.system, "ucontext_t"), else => false, }; -pub const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler")) - root.enable_segfault_handler -else - runtime_safety and have_segfault_handling_support; + +const enable_segfault_handler = std.options.enable_segfault_handler; +pub const default_enable_segfault_handler = runtime_safety and have_segfault_handling_support; pub fn maybeEnableSegfaultHandler() void { if (enable_segfault_handler) { diff --git a/lib/std/event/batch.zig b/lib/std/event/batch.zig index f5e3d393d4..9703a2512e 100644 --- a/lib/std/event/batch.zig +++ b/lib/std/event/batch.zig @@ -17,7 +17,7 @@ pub fn Batch( comptime async_behavior: enum { /// Observe the value of `std.io.is_async` to decide whether `add` /// and `wait` will be async functions. Asserts that the jobs do not suspend when - /// `std.io.mode == .blocking`. This is a generally safe assumption, and the + /// `std.options.io_mode == .blocking`. This is a generally safe assumption, and the /// usual recommended option for this parameter. auto_async, diff --git a/lib/std/event/loop.zig b/lib/std/event/loop.zig index 78ecb8c600..c851a9b80c 100644 --- a/lib/std/event/loop.zig +++ b/lib/std/event/loop.zig @@ -1,6 +1,5 @@ const std = @import("../std.zig"); const builtin = @import("builtin"); -const root = @import("root"); const assert = std.debug.assert; const testing = std.testing; const mem = std.mem; @@ -104,25 +103,29 @@ pub const Loop = struct { }; }; - const LoopOrVoid = switch (std.io.mode) { - .blocking => void, - .evented => Loop, + pub const Instance = switch (std.options.io_mode) { + .blocking => @TypeOf(null), + .evented => ?*Loop, }; + pub const instance = std.options.event_loop; - var global_instance_state: LoopOrVoid = undefined; - const default_instance: ?*LoopOrVoid = switch (std.io.mode) { + var global_instance_state: Loop = undefined; + pub const default_instance = switch (std.options.io_mode) { .blocking => null, .evented => &global_instance_state, }; - pub const instance: ?*LoopOrVoid = if (@hasDecl(root, "event_loop")) root.event_loop else default_instance; + + pub const Mode = enum { + single_threaded, + multi_threaded, + }; + pub const default_mode = .multi_threaded; /// TODO copy elision / named return values so that the threads referencing *Loop /// have the correct pointer value. /// https://github.com/ziglang/zig/issues/2761 and https://github.com/ziglang/zig/issues/2765 pub fn init(self: *Loop) !void { - if (builtin.single_threaded or - (@hasDecl(root, "event_loop_mode") and root.event_loop_mode == .single_threaded)) - { + if (builtin.single_threaded or std.options.event_loop_mode == .single_threaded) { return self.initSingleThreaded(); } else { return self.initMultiThreaded(); diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 3f0bd9d645..cc1b73acf2 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -2661,17 +2661,17 @@ pub fn cwd() Dir { if (builtin.os.tag == .windows) { return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle }; } else if (builtin.os.tag == .wasi) { - if (@hasDecl(root, "wasi_cwd")) { - return root.wasi_cwd(); - } else { - // Expect the first preopen to be current working directory. - return .{ .fd = 3 }; - } + return std.options.wasiCwd(); } else { return Dir{ .fd = os.AT.FDCWD }; } } +pub fn defaultWasiCwd() Dir { + // Expect the first preopen to be current working directory. + return .{ .fd = 3 }; +} + /// Opens a directory at the given path. The directory is a system resource that remains /// open until `close` is called on the result. /// See `openDirAbsoluteZ` for a function that accepts a null-terminated path. diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig index cb048adb30..a6ecc37d92 100644 --- a/lib/std/fs/file.zig +++ b/lib/std/fs/file.zig @@ -21,7 +21,7 @@ pub const File = struct { /// blocking. capable_io_mode: io.ModeOverride = io.default_mode, - /// Furthermore, even when `std.io.mode` is async, it is still sometimes desirable + /// Furthermore, even when `std.options.io_mode` is async, it is still sometimes desirable /// to perform blocking I/O, although not by default. For example, when printing a /// stack trace to stderr. This field tracks both by acting as an overriding I/O mode. /// When not building in async I/O mode, the type only has the `.blocking` tag, making diff --git a/lib/std/io.zig b/lib/std/io.zig index b12ca80142..d2a59a61a8 100644 --- a/lib/std/io.zig +++ b/lib/std/io.zig @@ -19,14 +19,7 @@ pub const Mode = enum { evented, }; -/// The application's chosen I/O mode. This defaults to `Mode.blocking` but can be overridden -/// by `root.event_loop`. -pub const mode: Mode = if (@hasDecl(root, "io_mode")) - root.io_mode -else if (@hasDecl(root, "event_loop")) - Mode.evented -else - Mode.blocking; +const mode = std.options.io_mode; pub const is_async = mode != .blocking; /// This is an enum value to use for I/O mode at runtime, since it takes up zero bytes at runtime, diff --git a/lib/std/log.zig b/lib/std/log.zig index 1d1b514c03..48a287a4ee 100644 --- a/lib/std/log.zig +++ b/lib/std/log.zig @@ -1,6 +1,6 @@ //! std.log is a standardized interface for logging which allows for the logging //! of programs and libraries using this interface to be formatted and filtered -//! by the implementer of the root.log function. +//! by the implementer of the `std.options.logFn` function. //! //! Each log message has an associated scope enum, which can be used to give //! context to the logging. The logging functions in std.log implicitly use a @@ -13,16 +13,20 @@ //! `const log = std.log.scoped(.libfoo);` to use .libfoo as the scope of its //! log messages. //! -//! An example root.log might look something like this: +//! An example `logFn` might look something like this: //! //! ``` //! const std = @import("std"); //! -//! // Set the log level to info -//! pub const log_level: std.log.Level = .info; +//! pub const std_options = struct { +//! // Set the log level to info +//! pub const log_level = .info; //! -//! // Define root.log to override the std implementation -//! pub fn log( +//! // Define logFn to override the std implementation +//! pub const logFn = myLogFn; +//! }; +//! +//! pub fn myLogFn( //! comptime level: std.log.Level, //! comptime scope: @TypeOf(.EnumLiteral), //! comptime format: []const u8, @@ -70,7 +74,6 @@ const std = @import("std.zig"); const builtin = @import("builtin"); -const root = @import("root"); pub const Level = enum { /// Error: something has gone wrong. This might be recoverable or might @@ -102,22 +105,14 @@ pub const default_level: Level = switch (builtin.mode) { .ReleaseFast, .ReleaseSmall => .err, }; -/// The current log level. This is set to root.log_level if present, otherwise -/// log.default_level. -pub const level: Level = if (@hasDecl(root, "log_level")) - root.log_level -else - default_level; +const level = std.options.log_level; pub const ScopeLevel = struct { scope: @Type(.EnumLiteral), level: Level, }; -const scope_levels = if (@hasDecl(root, "scope_levels")) - root.scope_levels -else - [0]ScopeLevel{}; +const scope_levels = std.options.log_scope_levels; fn log( comptime message_level: Level, @@ -127,13 +122,7 @@ fn log( ) void { if (comptime !logEnabled(message_level, scope)) return; - if (@hasDecl(root, "log")) { - if (@typeInfo(@TypeOf(root.log)) != .Fn) - @compileError("Expected root.log to be a function"); - root.log(message_level, scope, format, args); - } else { - defaultLog(message_level, scope, format, args); - } + std.options.logFn(message_level, scope, format, args); } /// Determine if a specific log message level and scope combination are enabled for logging. @@ -149,8 +138,8 @@ pub fn defaultLogEnabled(comptime message_level: Level) bool { return comptime logEnabled(message_level, default_log_scope); } -/// The default implementation for root.log. root.log may forward log messages -/// to this function. +/// The default implementation for the log function, custom log functions may +/// forward log messages to this function. pub fn defaultLog( comptime message_level: Level, comptime scope: @Type(.EnumLiteral), diff --git a/lib/std/start.zig b/lib/std/start.zig index 1a223b9a21..8aef63332d 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -527,7 +527,7 @@ const bad_main_ret = "expected return type of main to be 'void', '!void', 'noret // and we want fewer call frames in stack traces. inline fn initEventLoopAndCallMain() u8 { if (std.event.Loop.instance) |loop| { - if (!@hasDecl(root, "event_loop")) { + if (loop == std.event.Loop.default_instance) { loop.init() catch |err| { std.log.err("{s}", .{@errorName(err)}); if (@errorReturnTrace()) |trace| { @@ -556,7 +556,7 @@ inline fn initEventLoopAndCallMain() u8 { // because it is working around stage1 compiler bugs. inline fn initEventLoopAndCallWinMain() std.os.windows.INT { if (std.event.Loop.instance) |loop| { - if (!@hasDecl(root, "event_loop")) { + if (loop == std.event.Loop.default_instance) { loop.init() catch |err| { std.log.err("{s}", .{@errorName(err)}); if (@errorReturnTrace()) |trace| { diff --git a/lib/std/std.zig b/lib/std/std.zig index 1cbcd6bad7..22e0d96373 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -94,10 +94,79 @@ pub const wasm = @import("wasm.zig"); pub const zig = @import("zig.zig"); pub const start = @import("start.zig"); +const root = @import("root"); +const options_override = if (@hasDecl(root, "std_options")) root.std_options else struct {}; + +pub const options = struct { + pub const enable_segfault_handler: bool = if (@hasDecl(options_override, "enable_segfault_handler")) + options_override.enable_segfault_handler + else + debug.default_enable_segfault_handler; + + /// Function used to implement std.fs.cwd for wasi. + pub const wasiCwd: fn () fs.Dir = if (@hasDecl(options_override, "wasiCwd")) + options_override.wasiCwd + else + fs.defaultWasiCwd; + + /// The application's chosen I/O mode. + pub const io_mode: io.Mode = if (@hasDecl(options_override, "io_mode")) + options_override.io_mode + else if (@hasDecl(options_override, "event_loop")) + .evented + else + .blocking; + + pub const event_loop: event.Loop.Instance = if (@hasDecl(options_override, "event_loop")) + options_override.event_loop + else + event.Loop.default_instance; + + pub const event_loop_mode: event.Loop.Mode = if (@hasDecl(options_override, "event_loop_mode")) + options_override.event_loop_mode + else + event.Loop.default_mode; + + /// The current log level. + pub const log_level: log.Level = if (@hasDecl(options_override, "log_level")) + options_override.log_level + else + log.default_level; + + pub const log_scope_levels: []const log.ScopeLevel = if (@hasDecl(options_override, "log_scope_levels")) + options_override.log_scope_levels + else + &.{}; + + pub const logFn: fn ( + comptime message_level: log.Level, + comptime scope: @TypeOf(.enum_literal), + comptime format: []const u8, + args: anytype, + ) void = if (@hasDecl(options_override, "logFn")) + options_override.logFn + else + log.defaultLog; + + pub const cryptoRandomSeed: fn (buffer: []u8) void = if (@hasDecl(options_override, "cryptoRandomSeed")) + options_override.cryptoRandomSeed + else + @import("crypto/tlcsprng.zig").defaultRandomSeed; + + pub const crypto_always_getrandom: bool = if (@hasDecl(options_override, "crypto_always_getrandom")) + options_override.crypto_always_getrandom + else + false; +}; + // This forces the start.zig file to be imported, and the comptime logic inside that // file decides whether to export any appropriate start symbols, and call main. comptime { _ = start; + + for (@typeInfo(options_override).Struct.decls) |decl| { + if (!@hasDecl(options, decl.name)) @compileError("no option named " ++ decl.name); + } } test { diff --git a/lib/test_runner.zig b/lib/test_runner.zig index 7c3d4d493f..d1e5683c98 100644 --- a/lib/test_runner.zig +++ b/lib/test_runner.zig @@ -2,7 +2,10 @@ const std = @import("std"); const io = std.io; const builtin = @import("builtin"); -pub const io_mode: io.Mode = builtin.test_io_mode; +pub const std_options = struct { + pub const io_mode: io.Mode = builtin.test_io_mode; + pub const logFn = log; +}; var log_err_count: usize = 0; @@ -45,7 +48,7 @@ pub fn main() void { if (!have_tty) { std.debug.print("{d}/{d} {s}... ", .{ i + 1, test_fn_list.len, test_fn.name }); } - const result = if (test_fn.async_frame_size) |size| switch (io_mode) { + const result = if (test_fn.async_frame_size) |size| switch (std.options.io_mode) { .evented => blk: { if (async_frame_buffer.len < size) { std.heap.page_allocator.free(async_frame_buffer); diff --git a/src/crash_report.zig b/src/crash_report.zig index ba08db8266..6f657a9e01 100644 --- a/src/crash_report.zig +++ b/src/crash_report.zig @@ -13,12 +13,10 @@ const Decl = Module.Decl; pub const is_enabled = builtin.mode == .Debug; -/// To use these crash report diagnostics, publish these symbols in your main file. +/// To use these crash report diagnostics, publish this panic in your main file +/// and add `pub const enable_segfault_handler = false;` to your `std_options`. /// You will also need to call initialize() on startup, preferably as the very first operation in your program. -pub const root_decls = struct { - pub const panic = if (is_enabled) compilerPanic else std.builtin.default_panic; - pub const enable_segfault_handler = false; -}; +pub const panic = if (is_enabled) compilerPanic else std.builtin.default_panic; /// Install signal handlers to identify crashes and report diagnostics. pub fn initialize() void { diff --git a/src/main.zig b/src/main.zig index 421164de1c..814e60f97a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -25,11 +25,23 @@ const target_util = @import("target.zig"); const ThreadPool = @import("ThreadPool.zig"); const crash_report = @import("crash_report.zig"); -// Crash report needs to override the panic handler and other root decls -pub usingnamespace crash_report.root_decls; +pub const std_options = struct { + pub const wasiCwd = wasi_cwd; + pub const logFn = log; + pub const enable_segfault_handler = false; + + pub const log_level: std.log.Level = switch (builtin.mode) { + .Debug => .debug, + .ReleaseSafe, .ReleaseFast => .info, + .ReleaseSmall => .err, + }; +}; + +// Crash report needs to override the panic handler +pub const panic = crash_report.panic; var wasi_preopens: fs.wasi.Preopens = undefined; -pub inline fn wasi_cwd() fs.Dir { +pub fn wasi_cwd() fs.Dir { // Expect the first preopen to be current working directory. const cwd_fd: std.os.fd_t = 3; assert(mem.eql(u8, wasi_preopens.names[cwd_fd], ".")); @@ -111,12 +123,6 @@ const debug_usage = normal_usage ++ const usage = if (debug_extensions_enabled) debug_usage else normal_usage; -pub const log_level: std.log.Level = switch (builtin.mode) { - .Debug => .debug, - .ReleaseSafe, .ReleaseFast => .info, - .ReleaseSmall => .err, -}; - var log_scopes: std.ArrayListUnmanaged([]const u8) = .{}; pub fn log( @@ -128,7 +134,7 @@ pub fn log( // Hide debug messages unless: // * logging enabled with `-Dlog`. // * the --debug-log arg for the scope has been provided - if (@enumToInt(level) > @enumToInt(std.log.level) or + if (@enumToInt(level) > @enumToInt(std.options.log_level) or @enumToInt(level) > @enumToInt(std.log.Level.info)) { if (!build_options.enable_logging) return; diff --git a/test/behavior/pointers.zig b/test/behavior/pointers.zig index 36f70e1a77..e718169731 100644 --- a/test/behavior/pointers.zig +++ b/test/behavior/pointers.zig @@ -509,8 +509,8 @@ test "ptrCast comptime known slice to C pointer" { test "ptrToInt on a generic function" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag != .linux) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag != .linux) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO const S = struct { fn generic(i: anytype) @TypeOf(i) { diff --git a/test/compare_output.zig b/test/compare_output.zig index c2bfdf8062..b3a6144729 100644 --- a/test/compare_output.zig +++ b/test/compare_output.zig @@ -440,11 +440,14 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { cases.add("std.log per scope log level override", \\const std = @import("std"); \\ - \\pub const log_level: std.log.Level = .debug; - \\ - \\pub const scope_levels = [_]std.log.ScopeLevel{ - \\ .{ .scope = .a, .level = .warn }, - \\ .{ .scope = .c, .level = .err }, + \\pub const std_options = struct { + \\ pub const log_level: std.log.Level = .debug; + \\ + \\ pub const log_scope_levels = &[_]std.log.ScopeLevel{ + \\ .{ .scope = .a, .level = .warn }, + \\ .{ .scope = .c, .level = .err }, + \\ }; + \\ pub const logFn = log; \\}; \\ \\const loga = std.log.scoped(.a); @@ -494,7 +497,10 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { cases.add("std.heap.LoggingAllocator logs to std.log", \\const std = @import("std"); \\ - \\pub const log_level: std.log.Level = .debug; + \\pub const std_options = struct { + \\ pub const log_level: std.log.Level = .debug; + \\ pub const logFn = log; + \\}; \\ \\pub fn main() !void { \\ var allocator_buf: [10]u8 = undefined; diff --git a/test/standalone/issue_7030/main.zig b/test/standalone/issue_7030/main.zig index 4cf79a7b31..8a4146e84a 100644 --- a/test/standalone/issue_7030/main.zig +++ b/test/standalone/issue_7030/main.zig @@ -1,5 +1,9 @@ const std = @import("std"); +pub const std_options = struct { + pub const logFn = log; +}; + pub fn log( comptime message_level: std.log.Level, comptime scope: @Type(.EnumLiteral), diff --git a/test/standalone/issue_9693/main.zig b/test/standalone/issue_9693/main.zig index ecf410a1ca..19e9c5b96c 100644 --- a/test/standalone/issue_9693/main.zig +++ b/test/standalone/issue_9693/main.zig @@ -1,2 +1,4 @@ -pub const io_mode = .evented; +pub const std_options = struct { + pub const io_mode = .evented; +}; pub fn main() void {} |
