std: different mechanism for disabling network dependency

On Windows, it is sometimes problematic to depend on ws2_32.dll. Before,
users of std.Io.Threaded would have to call ioBasic() rather than io()
in order to avoid unnecessary dependencies on ws2_32.dll. Now, the
application can disable networking with std.Options.

This change is necessary due to moving networking functionality to
be based on Io.Operation, which is a tagged union.
This commit is contained in:
Andrew Kelley 2026-03-05 19:24:55 -08:00
parent 9c9af37a0c
commit 0403f9647b
40 changed files with 119 additions and 228 deletions

View file

@ -17,7 +17,7 @@ var fba: std.heap.FixedBufferAllocator = .init(&fba_buffer);
var fba_buffer: [8192]u8 = undefined;
var stdin_buffer: [4096]u8 = undefined;
var stdout_buffer: [4096]u8 = undefined;
const runner_threaded_io: Io = Io.Threaded.global_single_threaded.ioBasic();
const runner_threaded_io: Io = Io.Threaded.global_single_threaded.io();
/// Keep in sync with logic in `std.Build.addRunArtifact` which decides whether
/// the test runner will communicate with the build runner via `std.zig.Server`.

View file

@ -17,7 +17,7 @@ else
null;
pub const std_options_debug_io: std.Io = if (builtin.is_test)
std.Io.Threaded.global_single_threaded.ioBasic()
std.Io.Threaded.global_single_threaded.io()
else
unreachable;

View file

@ -13,7 +13,7 @@ pub const std_options = std.Options{
.logFn = logOverride,
};
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
fn logOverride(
comptime level: std.log.Level,

View file

@ -1907,141 +1907,10 @@ pub fn io(t: *Threaded) Io {
};
}
/// Same as `io` but disables all networking functionality, which has
/// an additional dependency on Windows (ws2_32).
pub fn ioBasic(t: *Threaded) Io {
return .{
.userdata = t,
.vtable = &.{
.crashHandler = crashHandler,
.async = async,
.concurrent = concurrent,
.await = await,
.cancel = cancel,
.groupAsync = groupAsync,
.groupConcurrent = groupConcurrent,
.groupAwait = groupAwait,
.groupCancel = groupCancel,
.recancel = recancel,
.swapCancelProtection = swapCancelProtection,
.checkCancel = checkCancel,
.futexWait = futexWait,
.futexWaitUncancelable = futexWaitUncancelable,
.futexWake = futexWake,
.operate = operate,
.batchAwaitAsync = batchAwaitAsync,
.batchAwaitConcurrent = batchAwaitConcurrent,
.batchCancel = batchCancel,
.dirCreateDir = dirCreateDir,
.dirCreateDirPath = dirCreateDirPath,
.dirCreateDirPathOpen = dirCreateDirPathOpen,
.dirStat = dirStat,
.dirStatFile = dirStatFile,
.dirAccess = dirAccess,
.dirCreateFile = dirCreateFile,
.dirCreateFileAtomic = dirCreateFileAtomic,
.dirOpenFile = dirOpenFile,
.dirOpenDir = dirOpenDir,
.dirClose = dirClose,
.dirRead = dirRead,
.dirRealPath = dirRealPath,
.dirRealPathFile = dirRealPathFile,
.dirDeleteFile = dirDeleteFile,
.dirDeleteDir = dirDeleteDir,
.dirRename = dirRename,
.dirRenamePreserve = dirRenamePreserve,
.dirSymLink = dirSymLink,
.dirReadLink = dirReadLink,
.dirSetOwner = dirSetOwner,
.dirSetFileOwner = dirSetFileOwner,
.dirSetPermissions = dirSetPermissions,
.dirSetFilePermissions = dirSetFilePermissions,
.dirSetTimestamps = dirSetTimestamps,
.dirHardLink = dirHardLink,
.fileStat = fileStat,
.fileLength = fileLength,
.fileClose = fileClose,
.fileWritePositional = fileWritePositional,
.fileWriteFileStreaming = fileWriteFileStreaming,
.fileWriteFilePositional = fileWriteFilePositional,
.fileReadPositional = fileReadPositional,
.fileSeekBy = fileSeekBy,
.fileSeekTo = fileSeekTo,
.fileSync = fileSync,
.fileIsTty = fileIsTty,
.fileEnableAnsiEscapeCodes = fileEnableAnsiEscapeCodes,
.fileSupportsAnsiEscapeCodes = fileSupportsAnsiEscapeCodes,
.fileSetLength = fileSetLength,
.fileSetOwner = fileSetOwner,
.fileSetPermissions = fileSetPermissions,
.fileSetTimestamps = fileSetTimestamps,
.fileLock = fileLock,
.fileTryLock = fileTryLock,
.fileUnlock = fileUnlock,
.fileDowngradeLock = fileDowngradeLock,
.fileRealPath = fileRealPath,
.fileHardLink = fileHardLink,
.fileMemoryMapCreate = fileMemoryMapCreate,
.fileMemoryMapDestroy = fileMemoryMapDestroy,
.fileMemoryMapSetLength = fileMemoryMapSetLength,
.fileMemoryMapRead = fileMemoryMapRead,
.fileMemoryMapWrite = fileMemoryMapWrite,
.processExecutableOpen = processExecutableOpen,
.processExecutablePath = processExecutablePath,
.lockStderr = lockStderr,
.tryLockStderr = tryLockStderr,
.unlockStderr = unlockStderr,
.processCurrentPath = processCurrentPath,
.processSetCurrentDir = processSetCurrentDir,
.processReplace = processReplace,
.processReplacePath = processReplacePath,
.processSpawn = processSpawn,
.processSpawnPath = processSpawnPath,
.childWait = childWait,
.childKill = childKill,
.progressParentFile = progressParentFile,
.now = now,
.clockResolution = clockResolution,
.sleep = sleep,
.random = random,
.randomSecure = randomSecure,
.netListenIp = netListenIpUnavailable,
.netListenUnix = netListenUnixUnavailable,
.netAccept = netAcceptUnavailable,
.netBindIp = netBindIpUnavailable,
.netConnectIp = netConnectIpUnavailable,
.netSocketCreatePair = netSocketCreatePairUnavailable,
.netConnectUnix = netConnectUnixUnavailable,
.netClose = netCloseUnavailable,
.netShutdown = netShutdownUnavailable,
.netRead = netReadUnavailable,
.netWrite = netWriteUnavailable,
.netWriteFile = netWriteFileUnavailable,
.netSend = netSendUnavailable,
.netInterfaceNameResolve = netInterfaceNameResolveUnavailable,
.netInterfaceName = netInterfaceNameUnavailable,
.netLookup = netLookupUnavailable,
},
};
}
pub const socket_flags_unsupported = is_darwin or native_os == .haiku;
const have_accept4 = !socket_flags_unsupported;
const have_flock_open_flags = @hasField(posix.O, "EXLOCK");
const have_networking = native_os != .wasi;
const have_networking = std.options.networking and native_os != .wasi;
const have_flock = @TypeOf(posix.system.flock) != void;
const have_sendmmsg = native_os == .linux;
const have_futex = switch (builtin.cpu.arch) {
@ -2593,7 +2462,7 @@ fn futexWait(userdata: ?*anyopaque, ptr: *const u32, expected: u32, timeout: Io.
return;
}
const t: *Threaded = @ptrCast(@alignCast(userdata));
const t_io = ioBasic(t);
const t_io = io(t);
const timeout_ns: ?u64 = ns: {
const d = timeout.toDurationFromNow(t_io) orelse break :ns null;
break :ns std.math.lossyCast(u64, d.raw.toNanoseconds());
@ -2786,7 +2655,7 @@ fn batchAwaitAsync(userdata: ?*anyopaque, b: *Io.Batch) Io.Cancelable!void {
fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.AwaitConcurrentError!void {
const t: *Threaded = @ptrCast(@alignCast(userdata));
if (is_windows) {
const deadline: ?Io.Clock.Timestamp = timeout.toTimestamp(ioBasic(t));
const deadline: ?Io.Clock.Timestamp = timeout.toTimestamp(io(t));
try batchDrainSubmittedWindows(t, b, true);
while (b.pending.head != .none and b.completed.head == .none) {
var delay_interval: windows.LARGE_INTEGER = interval: {
@ -2896,7 +2765,7 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout
},
else => {},
}
const t_io = ioBasic(t);
const t_io = io(t);
const deadline = timeout.toTimestamp(t_io);
while (true) {
const timeout_ms: i32 = t: {
@ -3534,7 +3403,7 @@ fn dirCreateDirPathOpenPosix(
options: Dir.OpenOptions,
) Dir.CreateDirPathOpenError!Dir {
const t: *Threaded = @ptrCast(@alignCast(userdata));
const t_io = ioBasic(t);
const t_io = io(t);
return dirOpenDirPosix(t, dir, sub_path, options) catch |err| switch (err) {
error.FileNotFound => {
_ = try dir.createDirPathStatus(t_io, sub_path, permissions);
@ -3655,7 +3524,7 @@ fn dirCreateDirPathOpenWasi(
options: Dir.OpenOptions,
) Dir.CreateDirPathOpenError!Dir {
const t: *Threaded = @ptrCast(@alignCast(userdata));
const t_io = ioBasic(t);
const t_io = io(t);
return dirOpenDirWasi(t, dir, sub_path, options) catch |err| switch (err) {
error.FileNotFound => {
_ = try dir.createDirPathStatus(t_io, sub_path, permissions);
@ -4696,7 +4565,7 @@ fn dirCreateFileAtomic(
options: Dir.CreateFileAtomicOptions,
) Dir.CreateFileAtomicError!File.Atomic {
const t: *Threaded = @ptrCast(@alignCast(userdata));
const t_io = ioBasic(t);
const t_io = io(t);
// Linux has O_TMPFILE, but linkat() does not support AT_REPLACE, so it's
// useless when we have to make up a bogus path name to do the rename()
@ -10324,19 +10193,19 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) process.Execut
const rc = std.c._NSGetExecutablePath(&symlink_path_buf, &n);
if (rc != 0) return error.NameTooLong;
const symlink_path = std.mem.sliceTo(&symlink_path_buf, 0);
return Io.Dir.realPathFileAbsolute(ioBasic(t), symlink_path, out_buffer) catch |err| switch (err) {
return Io.Dir.realPathFileAbsolute(io(t), symlink_path, out_buffer) catch |err| switch (err) {
error.NetworkNotFound => unreachable, // Windows-only
error.FileBusy => unreachable, // Windows-only
else => |e| return e,
};
},
.linux, .serenity => return Io.Dir.readLinkAbsolute(ioBasic(t), "/proc/self/exe", out_buffer) catch |err| switch (err) {
.linux, .serenity => return Io.Dir.readLinkAbsolute(io(t), "/proc/self/exe", out_buffer) catch |err| switch (err) {
error.UnsupportedReparsePointType => unreachable, // Windows-only
error.NetworkNotFound => unreachable, // Windows-only
error.FileBusy => unreachable, // Windows-only
else => |e| return e,
},
.illumos => return Io.Dir.readLinkAbsolute(ioBasic(t), "/proc/self/path/a.out", out_buffer) catch |err| switch (err) {
.illumos => return Io.Dir.readLinkAbsolute(io(t), "/proc/self/path/a.out", out_buffer) catch |err| switch (err) {
error.UnsupportedReparsePointType => unreachable, // Windows-only
error.NetworkNotFound => unreachable, // Windows-only
error.FileBusy => unreachable, // Windows-only
@ -11698,7 +11567,7 @@ fn sleepPosix(timeout: Io.Timeout) Io.Cancelable!void {
}
fn sleepWasi(t: *Threaded, timeout: Io.Timeout) Io.Cancelable!void {
const t_io = ioBasic(t);
const t_io = io(t);
const w = std.os.wasi;
const clock: w.subscription_clock_t = if (timeout.toDurationFromNow(t_io)) |d| .{
@ -11727,7 +11596,7 @@ fn sleepWasi(t: *Threaded, timeout: Io.Timeout) Io.Cancelable!void {
}
fn sleepNanosleep(t: *Threaded, timeout: Io.Timeout) Io.Cancelable!void {
const t_io = ioBasic(t);
const t_io = io(t);
const sec_type = @typeInfo(posix.timespec).@"struct".fields[0].type;
const nsec_type = @typeInfo(posix.timespec).@"struct".fields[1].type;
@ -13359,7 +13228,7 @@ fn netReceiveWindowsOne(
data_buffer: []u8,
flags: net.ReceiveFlags,
) net.Socket.ReceiveError!void {
comptime assert(have_networking);
if (!have_networking) return error.NetworkDown;
var windows_flags: u32 =
@as(u32, if (flags.oob) ws2_32.MSG.OOB else 0) |
@ -13534,6 +13403,7 @@ fn netWriteWindows(
data: []const []const u8,
splat: usize,
) net.Stream.Writer.Error!usize {
if (!have_networking) return error.NetworkDown;
const t: *Threaded = @ptrCast(@alignCast(userdata));
comptime assert(is_windows);
@ -13656,6 +13526,7 @@ fn addBuf(v: []posix.iovec_const, i: *iovlen_t, bytes: []const u8) void {
}
fn netClose(userdata: ?*anyopaque, handles: []const net.Socket.Handle) void {
if (!have_networking) unreachable;
const t: *Threaded = @ptrCast(@alignCast(userdata));
_ = t;
switch (native_os) {
@ -13864,7 +13735,7 @@ fn netLookupUnavailable(
_ = host_name;
_ = options;
const t: *Threaded = @ptrCast(@alignCast(userdata));
resolved.close(ioBasic(t));
resolved.close(io(t));
return error.NetworkDown;
}
@ -14147,7 +14018,7 @@ fn tryLockStderr(userdata: ?*anyopaque, terminal_mode: ?Io.Terminal.Mode) Io.Can
fn initLockedStderr(t: *Threaded, terminal_mode: ?Io.Terminal.Mode) Io.Cancelable!Io.LockedStderr {
if (!t.stderr_writer_initialized) {
const io_t = ioBasic(t);
const io_t = io(t);
if (is_windows) t.stderr_writer.file = .stderr();
t.stderr_writer.io = io_t;
t.stderr_writer_initialized = true;

View file

@ -174,6 +174,9 @@ pub const Options = struct {
/// stack traces will just print an error to the relevant `Io.Writer` and return.
allow_stack_tracing: bool = !@import("builtin").strip_debug_info,
/// Allows disabling networking in std.Io implementations.
networking: bool = true,
/// TODO This is a separate decl instead of a field as a workaround around
/// compilation errors due to zig not being lazy enough.
pub const logTerminalMode: fn () Io.Terminal.Mode = log.defaultTerminalMode;
@ -202,7 +205,7 @@ pub const Options = struct {
/// implementation based on coroutines, one likely wants `std.debug.print`
/// to directly write to stderr without trying to interact with the code
/// being debugged.
pub const debug_io: Io = if (@hasDecl(root, "std_options_debug_io")) root.std_options_debug_io else debug_threaded_io.?.ioBasic();
pub const debug_io: Io = if (@hasDecl(root, "std_options_debug_io")) root.std_options_debug_io else debug_threaded_io.?.io();
/// Overrides `std.Io.File.Permissions`.
pub const FilePermissions: ?type = if (@hasDecl(root, "std_options_FilePermissions")) root.std_options_FilePermissions else null;

View file

@ -3,6 +3,10 @@ const builtin = @import("builtin");
const assert = std.debug.assert;
const panic = std.debug.panicExtra;
pub const std_options: std.Options = .{
.networking = false,
};
const SourceLocation = extern struct {
file_name: ?[*:0]const u8,
line: u32,

View file

@ -10,7 +10,7 @@ pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, foo);
}
const foo = "good morning\n";
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="good morning\n"
#update=add new declaration
@ -21,7 +21,7 @@ pub fn main() !void {
}
const foo = "good morning\n";
const bar = "good evening\n";
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="good morning\n"
#update=reference new declaration
@ -32,7 +32,7 @@ pub fn main() !void {
}
const foo = "good morning\n";
const bar = "good evening\n";
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="good evening\n"
#update=reference missing declaration
@ -43,7 +43,7 @@ pub fn main() !void {
}
const foo = "good morning\n";
const bar = "good evening\n";
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_error=main.zig:3:52: error: use of undeclared identifier 'qux'
#update=add missing declaration
@ -55,7 +55,7 @@ pub fn main() !void {
const foo = "good morning\n";
const bar = "good evening\n";
const qux = "good night\n";
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="good night\n"
#update=remove unused declarations
@ -65,5 +65,5 @@ pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, qux);
}
const qux = "good night\n";
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="good night\n"

View file

@ -10,7 +10,7 @@ pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, @This().foo);
}
const foo = "good morning\n";
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="good morning\n"
#update=add new declaration
@ -21,7 +21,7 @@ pub fn main() !void {
}
const foo = "good morning\n";
const bar = "good evening\n";
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="good morning\n"
#update=reference new declaration
@ -32,7 +32,7 @@ pub fn main() !void {
}
const foo = "good morning\n";
const bar = "good evening\n";
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="good evening\n"
#update=reference missing declaration
@ -43,7 +43,7 @@ pub fn main() !void {
}
const foo = "good morning\n";
const bar = "good evening\n";
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_error=main.zig:3:59: error: root source file struct 'main' has no member named 'qux'
#expect_error=main.zig:1:1: note: struct declared here
@ -56,7 +56,7 @@ pub fn main() !void {
const foo = "good morning\n";
const bar = "good evening\n";
const qux = "good night\n";
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="good night\n"
#update=remove unused declarations
@ -66,5 +66,5 @@ pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, @This().qux);
}
const qux = "good night\n";
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="good night\n"

View file

@ -11,7 +11,7 @@ pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, "success\n");
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#file=foo.zig
comptime {
_ = @import("bad.zig");
@ -34,5 +34,5 @@ pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, "success\n");
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="success\n"

View file

@ -10,7 +10,7 @@ const string = @embedFile("string.txt");
pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, string);
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#file=string.txt
Hello, World!
#expect_stdout="Hello, World!\n"
@ -31,7 +31,7 @@ const string = @embedFile("string.txt");
pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, "a hardcoded string\n");
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="a hardcoded string\n"
#update=re-introduce reference to file
@ -41,7 +41,7 @@ const string = @embedFile("string.txt");
pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, string);
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_error=main.zig:2:27: error: unable to open 'string.txt': FileNotFound
#update=recreate file

View file

@ -19,7 +19,7 @@ pub fn main() !void {
try stdout_writer.interface.print("{s}\n", .{@tagName(val)});
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="a\n"
#update=too many enum fields
#file=main.zig
@ -43,7 +43,7 @@ comptime {
std.debug.assert(@TypeOf(@intFromEnum(Foo.e)) == Tag);
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_error=main.zig:7:5: error: enumeration value '4' too large for type 'u2'
#update=increase tag size
#file=main.zig
@ -62,5 +62,5 @@ pub fn main() !void {
try stdout_writer.interface.print("{s}\n", .{@tagName(val)});
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="a\n"

View file

@ -21,7 +21,7 @@ pub fn main() !void {
try stdout_writer.interface.print("{}\n", .{S.bar});
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="123\n"
#update=add conflict
@ -44,7 +44,7 @@ pub fn main() !void {
try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_error=main.zig:6:5: error: exported symbol collision: foo
#expect_error=main.zig:1:1: note: other symbol here
@ -68,7 +68,7 @@ pub fn main() !void {
try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="123 456\n"
#update=put exports in decl
@ -94,7 +94,7 @@ pub fn main() !void {
try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="123 456\n"
#update=remove reference to exporting decl
@ -141,7 +141,7 @@ pub fn main() !void {
try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="123 456\n"
#update=reintroduce reference to exporting decl, introducing conflict
@ -167,7 +167,7 @@ pub fn main() !void {
try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_error=main.zig:5:5: error: exported symbol collision: bar
#expect_error=main.zig:2:1: note: other symbol here
#expect_error=main.zig:6:5: error: exported symbol collision: other

View file

@ -12,7 +12,7 @@ fn foo(x: u8) !void {
return stdout_writer.interface.print("{d}\n", .{x});
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="123\n"
#update=change function type
@ -25,7 +25,7 @@ fn foo(x: i64) !void {
return stdout_writer.interface.print("{d}\n", .{x});
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="123\n"
#update=change function argument
@ -38,5 +38,5 @@ fn foo(x: i64) !void {
return stdout_writer.interface.print("{d}\n", .{x});
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="-42\n"

View file

@ -4,7 +4,7 @@
#update=initial version
#file=main.zig
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
fn Printer(message: []const u8) type {
return struct {
fn print() !void {
@ -20,7 +20,7 @@ pub fn main() !void {
#update=change line number
#file=main.zig
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
fn Printer(message: []const u8) type {
return struct {

View file

@ -7,7 +7,7 @@ const std = @import("std");
pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, "foo\n");
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="foo\n"
#update=change line number
#file=main.zig
@ -16,5 +16,5 @@ const std = @import("std");
pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, "foo\n");
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="foo\n"

View file

@ -17,7 +17,7 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn {
std.process.exit(0);
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="panic message: integer overflow\n"
#update=change the panic handler body
@ -35,7 +35,7 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn {
std.process.exit(0);
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="new panic message: integer overflow\n"
#update=change the panic handler function value
@ -53,5 +53,5 @@ fn myPanicNew(msg: []const u8, _: ?usize) noreturn {
std.process.exit(0);
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="third panic message: integer overflow\n"

View file

@ -47,7 +47,7 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn {
std.process.exit(0);
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="panic message: integer overflow\n"
#update=change the panic handler body
@ -95,7 +95,7 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn {
std.process.exit(0);
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="new panic message: integer overflow\n"
#update=change the panic handler function value
@ -143,5 +143,5 @@ fn myPanicNew(msg: []const u8, _: ?usize) noreturn {
std.process.exit(0);
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="third panic message: integer overflow\n"

View file

@ -13,7 +13,7 @@ fn foo(x: u16) !void {
try stdout_writer.interface.print("0x{x}\n", .{x << 4});
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="0x3000\n"
#update=change to right shift
#file=main.zig
@ -25,5 +25,5 @@ fn foo(x: u16) !void {
try stdout_writer.interface.print("0x{x}\n", .{x >> 4});
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="0x130\n"

View file

@ -18,7 +18,7 @@ fn foo(val: *const S) !void {
);
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="100 200\n"
#update=change struct layout
@ -36,7 +36,7 @@ fn foo(val: *const S) !void {
);
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="100 200\n"
#update=change values
@ -54,5 +54,5 @@ fn foo(val: *const S) !void {
);
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="1234 5678\n"

View file

@ -10,7 +10,7 @@ const message: []const u8 = @import("message.zon");
pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, message);
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#file=message.zon
"Hello, World!\n"
#expect_stdout="Hello, World!\n"
@ -32,7 +32,7 @@ const message: []const u8 = @import("message.zon");
pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, "a hardcoded string\n");
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_error=message.zon:1:1: error: unable to load 'message.zon': FileNotFound
#expect_error=main.zig:2:37: note: file imported here
@ -48,5 +48,5 @@ const message: []const u8 = @import("message.zon");
pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, message);
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="We're back, World!\n"

View file

@ -6,7 +6,7 @@
#update=initial version
#file=main.zig
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, @import("foo.zon").message);
}

View file

@ -10,7 +10,7 @@ const std = @import("std");
pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="Hello, World!\n"
#update=add compile log
@ -20,7 +20,7 @@ pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
@compileLog("this is a log");
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_error=main.zig:4:5: error: found compile log statement
#expect_compile_log=@as(*const [13:0]u8, "this is a log")
@ -30,5 +30,5 @@ const std = @import("std");
pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="Hello, World!\n"

View file

@ -19,7 +19,7 @@ const std = @import("std");
pub fn hello() !void {
try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="Hello, World!\n"
#update=add new error
#file=foo.zig
@ -27,7 +27,7 @@ const std = @import("std");
pub fn hello() !void {
try std.Io.File.stdout().writeStreamingAll(io, hello_str);
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_error=foo.zig:3:52: error: use of undeclared identifier 'hello_str'
#update=fix the new error
#file=foo.zig
@ -36,5 +36,5 @@ const hello_str = "Hello, World! Again!\n";
pub fn hello() !void {
try std.Io.File.stdout().writeStreamingAll(io, hello_str);
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="Hello, World! Again!\n"

View file

@ -11,7 +11,7 @@ fn foo() !void {
try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="Hello, World!\n"
#update=make function inline
@ -23,7 +23,7 @@ inline fn foo() !void {
try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="Hello, World!\n"
#update=change string
@ -35,5 +35,5 @@ inline fn foo() !void {
try std.Io.File.stdout().writeStreamingAll(io, "Hello, `inline` World!\n");
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="Hello, `inline` World!\n"

View file

@ -6,7 +6,7 @@
#update=initial version
#file=main.zig
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, "good morning\n");
}
@ -14,7 +14,7 @@ pub fn main() !void {
#update=change the string
#file=main.zig
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, "おはようございます\n");
}

View file

@ -14,7 +14,7 @@ const std = @import("std");
fn hello() !void {
try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_error=main.zig:3:12: error: 'hello' is not marked 'pub'
#expect_error=foo.zig:2:1: note: declared here
@ -24,5 +24,5 @@ const std = @import("std");
pub fn hello() !void {
try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="Hello, World!\n"

View file

@ -13,7 +13,7 @@ pub fn main() !void {
inline fn getStr() []const u8 {
return "foo\n";
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="foo\n"
#update=change the string
#file=main.zig
@ -25,5 +25,5 @@ pub fn main() !void {
inline fn getStr() []const u8 {
return "bar\n";
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="bar\n"

View file

@ -16,7 +16,7 @@ fn foo() u32 {
fn bar() u32 {
return 123;
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="7 123\n"
#update=add newline
@ -33,5 +33,5 @@ fn foo() u32 {
fn bar() u32 {
return 123;
}
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="8 123\n"

View file

@ -7,7 +7,7 @@
#file=main.zig
const std = @import("std");
var some_enum: enum { first, second } = .first;
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));
}
@ -16,7 +16,7 @@ pub fn main() !void {
#file=main.zig
const std = @import("std");
var some_enum: enum { first, second } = .first;
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));
}

View file

@ -14,7 +14,7 @@ fn foo(recurse: bool) !void {
try stdout.writeStreamingAll(io, "non-recursive path\n");
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="non-recursive path\n"
#update=eliminate recursion and change argument
@ -28,5 +28,5 @@ fn foo(recurse: bool) !void {
try stdout.writeStreamingAll(io, "non-recursive path\n");
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="x==1\n"

View file

@ -14,7 +14,7 @@ pub fn main() !void {
try stdout_writer.interface.print("{}\n", .{@intFromEnum(MyEnum.foo)});
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="1\n"
#update=remove enum field
#file=main.zig
@ -27,6 +27,6 @@ pub fn main() !void {
try stdout_writer.interface.print("{}\n", .{@intFromEnum(MyEnum.foo)});
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_error=main.zig:7:69: error: enum 'main.MyEnum' has no member named 'foo'
#expect_error=main.zig:1:16: note: enum declared here

View file

@ -10,7 +10,7 @@ pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, a);
}
const a = "Hello, World!\n";
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="Hello, World!\n"
#update=introduce compile error
@ -20,7 +20,7 @@ pub fn main() !void {
try std.Io.File.stdout().writeStreamingAll(io, a);
}
const a = @compileError("bad a");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_error=main.zig:5:11: error: bad a
#update=remove error reference
@ -31,7 +31,7 @@ pub fn main() !void {
}
const a = @compileError("bad a");
const b = "Hi there!\n";
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="Hi there!\n"
#update=introduce and remove reference to error
@ -42,5 +42,5 @@ pub fn main() !void {
}
const a = "Back to a\n";
const b = @compileError("bad b");
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
#expect_stdout="Back to a\n"

View file

@ -46,6 +46,9 @@ pub fn build(b: *std.Build) void {
lib.root_module.addCSourceFile(.{ .file = b.path("shared_lib.c"), .flags = &.{"-gdwarf"} });
exe.root_module.linkLibrary(lib);
if (target.result.os.tag == .windows)
exe.root_module.linkSystemLibrary("ws2_32", .{});
const run = b.addRunArtifact(exe);
run.expectExitCode(0);
run.skip_foreign_checks = true;

View file

@ -26,7 +26,7 @@ pub fn main(init: std.process.Init) !void {
return error.BadUsage;
};
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
var dir = try std.Io.Dir.cwd().openDir(io, dir_path, .{});
defer dir.close(io);

View file

@ -21,7 +21,7 @@ pub fn main(init: std.process.Init) !void {
const dir_path = std.Io.Dir.path.dirname(path) orelse unreachable;
const basename = std.Io.Dir.path.basename(path);
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
var dir = try std.Io.Dir.cwd().openDir(io, dir_path, .{});
defer dir.close(io);

View file

@ -23,6 +23,9 @@ pub fn build(b: *std.Build) void {
}),
});
if (target.result.os.tag == .windows)
obj.root_module.linkSystemLibrary("ws2_32", .{});
const exe = b.addExecutable(.{
.name = "issue_5825",
.root_module = b.createModule(.{

View file

@ -16,6 +16,9 @@ pub fn build(b: *std.Build) void {
}),
});
if (target.result.os.tag == .windows)
obj.root_module.linkSystemLibrary("ws2_32", .{});
const exe = b.addExecutable(.{
.name = "test",
.root_module = b.createModule(.{

View file

@ -5,7 +5,7 @@ pub fn main(init: std.process.Init) !void {
if (args.len != 2) return error.BadUsage;
const path = args[1];
const io = std.Io.Threaded.global_single_threaded.ioBasic();
const io = std.Io.Threaded.global_single_threaded.io();
std.Io.Dir.cwd().access(io, path, .{}) catch return error.AccessFailed;
}

View file

@ -24,6 +24,9 @@ pub fn build(b: *std.Build) void {
}),
});
if (target.result.os.tag == .windows)
lib.root_module.linkSystemLibrary("ws2_32", .{});
const exe = b.addExecutable(.{
.name = exe_name,
.root_module = b.createModule(.{

View file

@ -101,6 +101,7 @@ pub fn build(b: *std.Build) !void {
.flags = &.{ "-DUNICODE", "-D_UNICODE" },
});
verify_msvc.root_module.linkLibrary(lib_msvc);
verify_msvc.root_module.linkSystemLibrary("ws2_32", .{});
verify_msvc.root_module.link_libc = true;
const run_msvc = b.addRunArtifact(fuzz);