The "byo os" mechanism currently expects signatures similar to POSIX such as pub fn write(fd: bits.fd_t, ptr: [*]const u8, len: usize) usize and expects an errno-like mechanism; rather than using the zig errors and slices.
std.os.write has this definition:
pub fn write(fd: fd_t, bytes: []const u8) WriteError!void {
This proposal needs to be more clear about what exactly it is proposing. As is, it's not clear enough for anyone to do anything about. Feel free to elaborate with examples and criteria for closing, and then re-open the issue.
I remember having to implement a fake errno function for these to work. The problem with this is that the BYOS layer fundamentally requires the same signature as the other OS layers, and so there's no good way to provide this improvement without a much larger structural change.
This proposal needs to be more clear about what exactly it is proposing. As is, it's not clear enough for anyone to do anything about.
In os.zig we do:
pub const system = if (@hasDecl(root, "os") and root.os != @This())
root.os.system
else if (builtin.link_libc)
std.c
else switch (builtin.os) {
.....
.linux => @import("os/linux.zig"),
.....
This means that when you "BYO os", you have to match the signatures in std.os.linux and std.c. The signature of std.os.linux.write is pub fn write(fd: i32, buf: [*]const u8, count: usize) usize; implementing that has all sorts of complexities in terms of stuffing errors into the return value or elsewhere, and providing a root.os.getErrno to match.
This issue is proposing that std.os.linux instead has the signature pub fn write(fd: fd_t, bytes: []const u8) WriteError!void and that when I bring my own OS: I implement that.
I propose to solve this that os.zig functions possibly forward their arguments directly. So we keep the root.os.system layer option, which matches other systems, but functions could be directly provided in root.os and get the zig layer. Does that make sense?
So for write, I'm proposing this change:
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -52,7 +52,7 @@ test "" {
/// Applications can override the `system` API layer in their root source file.
/// Otherwise, when linking libc, this is the C API.
/// When not linking libc, it is the OS-specific system interface.
-pub const system = if (@hasDecl(root, "os") and root.os != @This())
+pub const system = if (have_root_os)
root.os.system
else if (builtin.link_libc)
std.c
@@ -66,6 +66,7 @@ else switch (builtin.os) {
.windows => windows,
else => struct {},
};
+const have_root_os = @hasDecl(root, "os") and root.os != @This();
pub usingnamespace @import("os/bits.zig");
@@ -454,6 +455,9 @@ pub const WriteError = error{
/// TODO evented I/O integration is disabled until
/// https://github.com/ziglang/zig/issues/3557 is solved.
pub fn write(fd: fd_t, bytes: []const u8) WriteError!void {
+ if (have_root_os and @hasDecl(root.os, "write")) {
+ return root.os.write(fd, bytes);
+ }
if (builtin.os == .windows) {
return windows.WriteFile(fd, bytes);
}
With similar patches for nearly every std.os function.
+ if (have_root_os and @hasDecl(root.os, "write")) { + return root.os.write(fd, bytes); + }
I'm not sure I love the idea of every os function having that as a preamble.
Given that its followed by a windows implementation:
if (builtin.os == .windows) { return windows.WriteFile(fd, bytes); }
How can we have e.g. windows implement the os interface and dispatch to that? That way windows would be "using the BYO os" layer but obviously not BYO.
Most helpful comment
In os.zig we do:
This means that when you "BYO os", you have to match the signatures in
std.os.linuxandstd.c. The signature ofstd.os.linux.writeispub fn write(fd: i32, buf: [*]const u8, count: usize) usize; implementing that has all sorts of complexities in terms of stuffing errors into the return value or elsewhere, and providing aroot.os.getErrnoto match.This issue is proposing that
std.os.linuxinstead has the signaturepub fn write(fd: fd_t, bytes: []const u8) WriteError!voidand that when I bring my own OS: I implement that.