aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/std/crypto/tlcsprng.zig21
-rw-r--r--lib/std/debug.zig7
-rw-r--r--lib/std/event/batch.zig2
-rw-r--r--lib/std/event/loop.zig23
-rw-r--r--lib/std/fs.zig12
-rw-r--r--lib/std/fs/file.zig2
-rw-r--r--lib/std/io.zig9
-rw-r--r--lib/std/log.zig41
-rw-r--r--lib/std/start.zig4
-rw-r--r--lib/std/std.zig69
-rw-r--r--lib/test_runner.zig7
-rw-r--r--src/crash_report.zig8
-rw-r--r--src/main.zig26
-rw-r--r--test/behavior/pointers.zig4
-rw-r--r--test/compare_output.zig18
-rw-r--r--test/standalone/issue_7030/main.zig4
-rw-r--r--test/standalone/issue_9693/main.zig4
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 {}