authorgravatar for takeshi@tetrate.ioTakeshi Yoneda <takeshi@tetrate.io> 2021-07-27 08:59:34+09:00
committergravatar for takeshi@tetrate.ioTakeshi Yoneda <takeshi@tetrate.io> 2021-07-27 09:01:00+09:00
log1e20a62126e66d0306a6db01b3a2ffd6b946b9b6
treef324d0497c78a25144c06f4e2a9c69a2e3a5a658
parentfc105f268149b195ea4a4189da59d40e96e455b4

WASI,libc: enable tests.

Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>

16 files changed, 221 insertions(+), 86 deletions(-)

lib/std/Thread.zig+1-1
...@@ -24,7 +24,7 @@ pub const Condition = @import("Thread/Condition.zig");...@@ -24,7 +24,7 @@ pub const Condition = @import("Thread/Condition.zig");
2424
25pub const spinLoopHint = @compileError("deprecated: use std.atomic.spinLoopHint");25pub const spinLoopHint = @compileError("deprecated: use std.atomic.spinLoopHint");
2626
27pub const use_pthreads = target.os.tag != .windows and std.builtin.link_libc;27pub const use_pthreads = target.os.tag != .windows and std.Target.current.os.tag != .wasi and std.builtin.link_libc;
2828
29const Thread = @This();29const Thread = @This();
30const Impl = if (target.os.tag == .windows)30const Impl = if (target.os.tag == .windows)
lib/std/c.zig+2
...@@ -31,6 +31,7 @@ pub usingnamespace switch (std.Target.current.os.tag) {...@@ -31,6 +31,7 @@ pub usingnamespace switch (std.Target.current.os.tag) {
31 .fuchsia => @import("c/fuchsia.zig"),31 .fuchsia => @import("c/fuchsia.zig"),
32 .minix => @import("c/minix.zig"),32 .minix => @import("c/minix.zig"),
33 .emscripten => @import("c/emscripten.zig"),33 .emscripten => @import("c/emscripten.zig"),
34 .wasi => @import("c/wasi.zig"),
34 else => struct {},35 else => struct {},
35};36};
3637
...@@ -77,6 +78,7 @@ pub extern "c" fn fread(noalias ptr: [*]u8, size_of_type: usize, item_count: usi...@@ -77,6 +78,7 @@ pub extern "c" fn fread(noalias ptr: [*]u8, size_of_type: usize, item_count: usi
7778
78pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;79pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
79pub extern "c" fn abort() noreturn;80pub extern "c" fn abort() noreturn;
81
80pub extern "c" fn exit(code: c_int) noreturn;82pub extern "c" fn exit(code: c_int) noreturn;
81pub extern "c" fn _exit(code: c_int) noreturn;83pub extern "c" fn _exit(code: c_int) noreturn;
82pub extern "c" fn isatty(fd: fd_t) c_int;84pub extern "c" fn isatty(fd: fd_t) c_int;
lib/std/c/wasi.zig created+60
...@@ -0,0 +1,60 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6usingnamespace @import("../os/bits.zig");
7
8extern threadlocal var errno: c_int;
9
10pub fn _errno() *c_int {
11 return &errno;
12}
13
14pub const pid_t = c_int;
15pub const uid_t = u32;
16pub const gid_t = u32;
17pub const off_t = i64;
18
19pub const libc_stat = extern struct {
20 dev: i32,
21 ino: ino_t,
22 nlink: u64,
23
24 mode: mode_t,
25 uid: uid_t,
26 gid: gid_t,
27 __pad0: isize,
28 rdev: i32,
29 size: off_t,
30 blksize: i32,
31 blocks: i64,
32
33 atimesec: time_t,
34 atimensec: isize,
35 mtimesec: time_t,
36 mtimensec: isize,
37 ctimesec: time_t,
38 ctimensec: isize,
39
40 pub fn atime(self: @This()) timespec {
41 return timespec{
42 .tv_sec = self.atimesec,
43 .tv_nsec = self.atimensec,
44 };
45 }
46
47 pub fn mtime(self: @This()) timespec {
48 return timespec{
49 .tv_sec = self.mtimesec,
50 .tv_nsec = self.mtimensec,
51 };
52 }
53
54 pub fn ctime(self: @This()) timespec {
55 return timespec{
56 .tv_sec = self.ctimesec,
57 .tv_nsec = self.ctimensec,
58 };
59 }
60};
lib/std/fs.zig+31-24
...@@ -647,6 +647,9 @@ pub const Dir = struct {...@@ -647,6 +647,9 @@ pub const Dir = struct {
647 /// Memory such as file names referenced in this returned entry becomes invalid647 /// Memory such as file names referenced in this returned entry becomes invalid
648 /// with subsequent calls to `next`, as well as when this `Dir` is deinitialized.648 /// with subsequent calls to `next`, as well as when this `Dir` is deinitialized.
649 pub fn next(self: *Self) Error!?Entry {649 pub fn next(self: *Self) Error!?Entry {
650 // We intentinally use fd_readdir even when linked with libc,
651 // since its implementation is exactly the same as below,
652 // and we avoid the code complexity here.
650 const w = os.wasi;653 const w = os.wasi;
651 start_over: while (true) {654 start_over: while (true) {
652 if (self.index >= self.end_index) {655 if (self.index >= self.end_index) {
...@@ -770,7 +773,7 @@ pub const Dir = struct {...@@ -770,7 +773,7 @@ pub const Dir = struct {
770 const path_w = try os.windows.sliceToPrefixedFileW(sub_path);773 const path_w = try os.windows.sliceToPrefixedFileW(sub_path);
771 return self.openFileW(path_w.span(), flags);774 return self.openFileW(path_w.span(), flags);
772 }775 }
773 if (builtin.os.tag == .wasi) {776 if (builtin.os.tag == .wasi and !builtin.link_libc) {
774 return self.openFileWasi(sub_path, flags);777 return self.openFileWasi(sub_path, flags);
775 }778 }
776 const path_c = try os.toPosixPath(sub_path);779 const path_c = try os.toPosixPath(sub_path);
...@@ -846,14 +849,16 @@ pub const Dir = struct {...@@ -846,14 +849,16 @@ pub const Dir = struct {
846 try os.openatZ(self.fd, sub_path, os_flags, 0);849 try os.openatZ(self.fd, sub_path, os_flags, 0);
847 errdefer os.close(fd);850 errdefer os.close(fd);
848851
849 if (!has_flock_open_flags and flags.lock != .None) {852 if (builtin.target.os.tag != .wasi) {
850 // TODO: integrate async I/O853 if (!has_flock_open_flags and flags.lock != .None) {
851 const lock_nonblocking = if (flags.lock_nonblocking) os.LOCK_NB else @as(i32, 0);854 // TODO: integrate async I/O
852 try os.flock(fd, switch (flags.lock) {855 const lock_nonblocking = if (flags.lock_nonblocking) os.LOCK_NB else @as(i32, 0);
853 .None => unreachable,856 try os.flock(fd, switch (flags.lock) {
854 .Shared => os.LOCK_SH | lock_nonblocking,857 .None => unreachable,
855 .Exclusive => os.LOCK_EX | lock_nonblocking,858 .Shared => os.LOCK_SH | lock_nonblocking,
856 });859 .Exclusive => os.LOCK_EX | lock_nonblocking,
860 });
861 }
857 }862 }
858863
859 if (has_flock_open_flags and flags.lock_nonblocking) {864 if (has_flock_open_flags and flags.lock_nonblocking) {
...@@ -926,7 +931,7 @@ pub const Dir = struct {...@@ -926,7 +931,7 @@ pub const Dir = struct {
926 const path_w = try os.windows.sliceToPrefixedFileW(sub_path);931 const path_w = try os.windows.sliceToPrefixedFileW(sub_path);
927 return self.createFileW(path_w.span(), flags);932 return self.createFileW(path_w.span(), flags);
928 }933 }
929 if (builtin.os.tag == .wasi) {934 if (builtin.os.tag == .wasi and !builtin.link_libc) {
930 return self.createFileWasi(sub_path, flags);935 return self.createFileWasi(sub_path, flags);
931 }936 }
932 const path_c = try os.toPosixPath(sub_path);937 const path_c = try os.toPosixPath(sub_path);
...@@ -996,14 +1001,16 @@ pub const Dir = struct {...@@ -996,14 +1001,16 @@ pub const Dir = struct {
996 try os.openatZ(self.fd, sub_path_c, os_flags, flags.mode);1001 try os.openatZ(self.fd, sub_path_c, os_flags, flags.mode);
997 errdefer os.close(fd);1002 errdefer os.close(fd);
9981003
999 if (!has_flock_open_flags and flags.lock != .None) {1004 if (builtin.target.os.tag != .wasi) {
1000 // TODO: integrate async I/O1005 if (!has_flock_open_flags and flags.lock != .None and builtin.target.os.tag != .wasi) {
1001 const lock_nonblocking = if (flags.lock_nonblocking) os.LOCK_NB else @as(i32, 0);1006 // TODO: integrate async I/O
1002 try os.flock(fd, switch (flags.lock) {1007 const lock_nonblocking = if (flags.lock_nonblocking) os.LOCK_NB else @as(i32, 0);
1003 .None => unreachable,1008 try os.flock(fd, switch (flags.lock) {
1004 .Shared => os.LOCK_SH | lock_nonblocking,1009 .None => unreachable,
1005 .Exclusive => os.LOCK_EX | lock_nonblocking,1010 .Shared => os.LOCK_SH | lock_nonblocking,
1006 });1011 .Exclusive => os.LOCK_EX | lock_nonblocking,
1012 });
1013 }
1007 }1014 }
10081015
1009 if (has_flock_open_flags and flags.lock_nonblocking) {1016 if (has_flock_open_flags and flags.lock_nonblocking) {
...@@ -1284,7 +1291,7 @@ pub const Dir = struct {...@@ -1284,7 +1291,7 @@ pub const Dir = struct {
1284 if (builtin.os.tag == .windows) {1291 if (builtin.os.tag == .windows) {
1285 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);1292 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
1286 return self.openDirW(sub_path_w.span().ptr, args);1293 return self.openDirW(sub_path_w.span().ptr, args);
1287 } else if (builtin.os.tag == .wasi) {1294 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
1288 return self.openDirWasi(sub_path, args);1295 return self.openDirWasi(sub_path, args);
1289 } else {1296 } else {
1290 const sub_path_c = try os.toPosixPath(sub_path);1297 const sub_path_c = try os.toPosixPath(sub_path);
...@@ -1431,7 +1438,7 @@ pub const Dir = struct {...@@ -1431,7 +1438,7 @@ pub const Dir = struct {
1431 if (builtin.os.tag == .windows) {1438 if (builtin.os.tag == .windows) {
1432 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);1439 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
1433 return self.deleteFileW(sub_path_w.span());1440 return self.deleteFileW(sub_path_w.span());
1434 } else if (builtin.os.tag == .wasi) {1441 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
1435 os.unlinkatWasi(self.fd, sub_path, 0) catch |err| switch (err) {1442 os.unlinkatWasi(self.fd, sub_path, 0) catch |err| switch (err) {
1436 error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR1443 error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR
1437 else => |e| return e,1444 else => |e| return e,
...@@ -1494,7 +1501,7 @@ pub const Dir = struct {...@@ -1494,7 +1501,7 @@ pub const Dir = struct {
1494 if (builtin.os.tag == .windows) {1501 if (builtin.os.tag == .windows) {
1495 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);1502 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
1496 return self.deleteDirW(sub_path_w.span());1503 return self.deleteDirW(sub_path_w.span());
1497 } else if (builtin.os.tag == .wasi) {1504 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
1498 os.unlinkat(self.fd, sub_path, os.AT_REMOVEDIR) catch |err| switch (err) {1505 os.unlinkat(self.fd, sub_path, os.AT_REMOVEDIR) catch |err| switch (err) {
1499 error.IsDir => unreachable, // not possible since we pass AT_REMOVEDIR1506 error.IsDir => unreachable, // not possible since we pass AT_REMOVEDIR
1500 else => |e| return e,1507 else => |e| return e,
...@@ -1553,7 +1560,7 @@ pub const Dir = struct {...@@ -1553,7 +1560,7 @@ pub const Dir = struct {
1553 sym_link_path: []const u8,1560 sym_link_path: []const u8,
1554 flags: SymLinkFlags,1561 flags: SymLinkFlags,
1555 ) !void {1562 ) !void {
1556 if (builtin.os.tag == .wasi) {1563 if (builtin.os.tag == .wasi and !builtin.link_libc) {
1557 return self.symLinkWasi(target_path, sym_link_path, flags);1564 return self.symLinkWasi(target_path, sym_link_path, flags);
1558 }1565 }
1559 if (builtin.os.tag == .windows) {1566 if (builtin.os.tag == .windows) {
...@@ -1606,7 +1613,7 @@ pub const Dir = struct {...@@ -1606,7 +1613,7 @@ pub const Dir = struct {
1606 /// The return value is a slice of `buffer`, from index `0`.1613 /// The return value is a slice of `buffer`, from index `0`.
1607 /// Asserts that the path parameter has no null bytes.1614 /// Asserts that the path parameter has no null bytes.
1608 pub fn readLink(self: Dir, sub_path: []const u8, buffer: []u8) ![]u8 {1615 pub fn readLink(self: Dir, sub_path: []const u8, buffer: []u8) ![]u8 {
1609 if (builtin.os.tag == .wasi) {1616 if (builtin.os.tag == .wasi and !builtin.link_libc) {
1610 return self.readLinkWasi(sub_path, buffer);1617 return self.readLinkWasi(sub_path, buffer);
1611 }1618 }
1612 if (builtin.os.tag == .windows) {1619 if (builtin.os.tag == .windows) {
...@@ -2025,7 +2032,7 @@ pub const Dir = struct {...@@ -2025,7 +2032,7 @@ pub const Dir = struct {
2025pub fn cwd() Dir {2032pub fn cwd() Dir {
2026 if (builtin.os.tag == .windows) {2033 if (builtin.os.tag == .windows) {
2027 return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle };2034 return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle };
2028 } else if (builtin.os.tag == .wasi) {2035 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
2029 @compileError("WASI doesn't have a concept of cwd(); use std.fs.wasi.PreopenList to get available Dir handles instead");2036 @compileError("WASI doesn't have a concept of cwd(); use std.fs.wasi.PreopenList to get available Dir handles instead");
2030 } else {2037 } else {
2031 return Dir{ .fd = os.AT_FDCWD };2038 return Dir{ .fd = os.AT_FDCWD };
lib/std/fs/file.zig+17-20
...@@ -326,26 +326,23 @@ pub const File = struct {...@@ -326,26 +326,23 @@ pub const File = struct {
326 .inode = st.ino,326 .inode = st.ino,
327 .size = @bitCast(u64, st.size),327 .size = @bitCast(u64, st.size),
328 .mode = st.mode,328 .mode = st.mode,
329 .kind = switch (builtin.os.tag) {329 .kind = if (builtin.os.tag == .wasi and !builtin.link_libc) switch (st.filetype) {
330 .wasi => switch (st.filetype) {330 os.FILETYPE_BLOCK_DEVICE => Kind.BlockDevice,
331 os.FILETYPE_BLOCK_DEVICE => Kind.BlockDevice,331 os.FILETYPE_CHARACTER_DEVICE => Kind.CharacterDevice,
332 os.FILETYPE_CHARACTER_DEVICE => Kind.CharacterDevice,332 os.FILETYPE_DIRECTORY => Kind.Directory,
333 os.FILETYPE_DIRECTORY => Kind.Directory,333 os.FILETYPE_SYMBOLIC_LINK => Kind.SymLink,
334 os.FILETYPE_SYMBOLIC_LINK => Kind.SymLink,334 os.FILETYPE_REGULAR_FILE => Kind.File,
335 os.FILETYPE_REGULAR_FILE => Kind.File,335 os.FILETYPE_SOCKET_STREAM, os.FILETYPE_SOCKET_DGRAM => Kind.UnixDomainSocket,
336 os.FILETYPE_SOCKET_STREAM, os.FILETYPE_SOCKET_DGRAM => Kind.UnixDomainSocket,336 else => Kind.Unknown,
337 else => Kind.Unknown,337 } else switch (st.mode & os.S_IFMT) {
338 },338 os.S_IFBLK => Kind.BlockDevice,
339 else => switch (st.mode & os.S_IFMT) {339 os.S_IFCHR => Kind.CharacterDevice,
340 os.S_IFBLK => Kind.BlockDevice,340 os.S_IFDIR => Kind.Directory,
341 os.S_IFCHR => Kind.CharacterDevice,341 os.S_IFIFO => Kind.NamedPipe,
342 os.S_IFDIR => Kind.Directory,342 os.S_IFLNK => Kind.SymLink,
343 os.S_IFIFO => Kind.NamedPipe,343 os.S_IFREG => Kind.File,
344 os.S_IFLNK => Kind.SymLink,344 os.S_IFSOCK => Kind.UnixDomainSocket,
345 os.S_IFREG => Kind.File,345 else => Kind.Unknown,
346 os.S_IFSOCK => Kind.UnixDomainSocket,
347 else => Kind.Unknown,
348 },
349 },346 },
350 .atime = @as(i128, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec,347 .atime = @as(i128, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec,
351 .mtime = @as(i128, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec,348 .mtime = @as(i128, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec,
lib/std/fs/wasi.zig+1-1
...@@ -169,7 +169,7 @@ pub const PreopenList = struct {...@@ -169,7 +169,7 @@ pub const PreopenList = struct {
169};169};
170170
171test "extracting WASI preopens" {171test "extracting WASI preopens" {
172 if (std.builtin.os.tag != .wasi) return error.SkipZigTest;172 if (std.builtin.os.tag != .wasi or @import("builtin").link_libc) return error.SkipZigTest;
173173
174 var preopens = PreopenList.init(std.testing.allocator);174 var preopens = PreopenList.init(std.testing.allocator);
175 defer preopens.deinit();175 defer preopens.deinit();
lib/std/io/c_writer.zig+1-1
...@@ -35,7 +35,7 @@ fn cWriterWrite(c_file: *std.c.FILE, bytes: []const u8) std.fs.File.WriteError!u...@@ -35,7 +35,7 @@ fn cWriterWrite(c_file: *std.c.FILE, bytes: []const u8) std.fs.File.WriteError!u
35}35}
3636
37test {37test {
38 if (!builtin.link_libc) return error.SkipZigTest;38 if (!builtin.link_libc or builtin.os.tag == .wasi) return error.SkipZigTest;
3939
40 const filename = "tmp_io_test_file.txt";40 const filename = "tmp_io_test_file.txt";
41 const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile;41 const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile;
lib/std/os.zig+25-22
...@@ -404,7 +404,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {...@@ -404,7 +404,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
404 const first = iov[0];404 const first = iov[0];
405 return read(fd, first.iov_base[0..first.iov_len]);405 return read(fd, first.iov_base[0..first.iov_len]);
406 }406 }
407 if (builtin.os.tag == .wasi) {407 if (builtin.os.tag == .wasi and !builtin.link_libc) {
408 var nread: usize = undefined;408 var nread: usize = undefined;
409 switch (wasi.fd_read(fd, iov.ptr, iov.len, &nread)) {409 switch (wasi.fd_read(fd, iov.ptr, iov.len, &nread)) {
410 wasi.ESUCCESS => return nread,410 wasi.ESUCCESS => return nread,
...@@ -461,7 +461,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {...@@ -461,7 +461,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
461 if (builtin.os.tag == .windows) {461 if (builtin.os.tag == .windows) {
462 return windows.ReadFile(fd, buf, offset, std.io.default_mode);462 return windows.ReadFile(fd, buf, offset, std.io.default_mode);
463 }463 }
464 if (builtin.os.tag == .wasi) {464 if (builtin.os.tag == .wasi and !builtin.link_libc) {
465 const iovs = [1]iovec{iovec{465 const iovs = [1]iovec{iovec{
466 .iov_base = buf.ptr,466 .iov_base = buf.ptr,
467 .iov_len = buf.len,467 .iov_len = buf.len,
...@@ -556,7 +556,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {...@@ -556,7 +556,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
556 else => return windows.unexpectedStatus(rc),556 else => return windows.unexpectedStatus(rc),
557 }557 }
558 }558 }
559 if (std.Target.current.os.tag == .wasi) {559 if (std.Target.current.os.tag == .wasi and !builtin.link_libc) {
560 switch (wasi.fd_filestat_set_size(fd, length)) {560 switch (wasi.fd_filestat_set_size(fd, length)) {
561 wasi.ESUCCESS => return,561 wasi.ESUCCESS => return,
562 wasi.EINTR => unreachable,562 wasi.EINTR => unreachable,
...@@ -617,7 +617,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {...@@ -617,7 +617,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
617 const first = iov[0];617 const first = iov[0];
618 return pread(fd, first.iov_base[0..first.iov_len], offset);618 return pread(fd, first.iov_base[0..first.iov_len], offset);
619 }619 }
620 if (builtin.os.tag == .wasi) {620 if (builtin.os.tag == .wasi and !builtin.link_libc) {
621 var nread: usize = undefined;621 var nread: usize = undefined;
622 switch (wasi.fd_pread(fd, iov.ptr, iov.len, offset, &nread)) {622 switch (wasi.fd_pread(fd, iov.ptr, iov.len, offset, &nread)) {
623 wasi.ESUCCESS => return nread,623 wasi.ESUCCESS => return nread,
...@@ -795,7 +795,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {...@@ -795,7 +795,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
795 const first = iov[0];795 const first = iov[0];
796 return write(fd, first.iov_base[0..first.iov_len]);796 return write(fd, first.iov_base[0..first.iov_len]);
797 }797 }
798 if (builtin.os.tag == .wasi) {798 if (builtin.os.tag == .wasi and !builtin.link_libc) {
799 var nwritten: usize = undefined;799 var nwritten: usize = undefined;
800 switch (wasi.fd_write(fd, iov.ptr, iov.len, &nwritten)) {800 switch (wasi.fd_write(fd, iov.ptr, iov.len, &nwritten)) {
801 wasi.ESUCCESS => return nwritten,801 wasi.ESUCCESS => return nwritten,
...@@ -867,7 +867,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {...@@ -867,7 +867,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
867 if (std.Target.current.os.tag == .windows) {867 if (std.Target.current.os.tag == .windows) {
868 return windows.WriteFile(fd, bytes, offset, std.io.default_mode);868 return windows.WriteFile(fd, bytes, offset, std.io.default_mode);
869 }869 }
870 if (builtin.os.tag == .wasi) {870 if (builtin.os.tag == .wasi and !builtin.link_libc) {
871 const ciovs = [1]iovec_const{iovec_const{871 const ciovs = [1]iovec_const{iovec_const{
872 .iov_base = bytes.ptr,872 .iov_base = bytes.ptr,
873 .iov_len = bytes.len,873 .iov_len = bytes.len,
...@@ -968,7 +968,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz...@@ -968,7 +968,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
968 const first = iov[0];968 const first = iov[0];
969 return pwrite(fd, first.iov_base[0..first.iov_len], offset);969 return pwrite(fd, first.iov_base[0..first.iov_len], offset);
970 }970 }
971 if (builtin.os.tag == .wasi) {971 if (builtin.os.tag == .wasi and !builtin.link_libc) {
972 var nwritten: usize = undefined;972 var nwritten: usize = undefined;
973 switch (wasi.fd_pwrite(fd, iov.ptr, iov.len, offset, &nwritten)) {973 switch (wasi.fd_pwrite(fd, iov.ptr, iov.len, offset, &nwritten)) {
974 wasi.ESUCCESS => return nwritten,974 wasi.ESUCCESS => return nwritten,
...@@ -1627,7 +1627,7 @@ pub fn symlinkZ(target_path: [*:0]const u8, sym_link_path: [*:0]const u8) SymLin...@@ -1627,7 +1627,7 @@ pub fn symlinkZ(target_path: [*:0]const u8, sym_link_path: [*:0]const u8) SymLin
1627/// If `sym_link_path` exists, it will not be overwritten.1627/// If `sym_link_path` exists, it will not be overwritten.
1628/// See also `symlinkatWasi`, `symlinkatZ` and `symlinkatW`.1628/// See also `symlinkatWasi`, `symlinkatZ` and `symlinkatW`.
1629pub fn symlinkat(target_path: []const u8, newdirfd: fd_t, sym_link_path: []const u8) SymLinkError!void {1629pub fn symlinkat(target_path: []const u8, newdirfd: fd_t, sym_link_path: []const u8) SymLinkError!void {
1630 if (builtin.os.tag == .wasi) {1630 if (builtin.os.tag == .wasi and !builtin.link_libc) {
1631 return symlinkatWasi(target_path, newdirfd, sym_link_path);1631 return symlinkatWasi(target_path, newdirfd, sym_link_path);
1632 }1632 }
1633 if (builtin.os.tag == .windows) {1633 if (builtin.os.tag == .windows) {
...@@ -1856,7 +1856,7 @@ pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!vo...@@ -1856,7 +1856,7 @@ pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!vo
1856 if (builtin.os.tag == .windows) {1856 if (builtin.os.tag == .windows) {
1857 const file_path_w = try windows.sliceToPrefixedFileW(file_path);1857 const file_path_w = try windows.sliceToPrefixedFileW(file_path);
1858 return unlinkatW(dirfd, file_path_w.span(), flags);1858 return unlinkatW(dirfd, file_path_w.span(), flags);
1859 } else if (builtin.os.tag == .wasi) {1859 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
1860 return unlinkatWasi(dirfd, file_path, flags);1860 return unlinkatWasi(dirfd, file_path, flags);
1861 } else {1861 } else {
1862 const file_path_c = try toPosixPath(file_path);1862 const file_path_c = try toPosixPath(file_path);
...@@ -2023,7 +2023,7 @@ pub fn renameat(...@@ -2023,7 +2023,7 @@ pub fn renameat(
2023 const old_path_w = try windows.sliceToPrefixedFileW(old_path);2023 const old_path_w = try windows.sliceToPrefixedFileW(old_path);
2024 const new_path_w = try windows.sliceToPrefixedFileW(new_path);2024 const new_path_w = try windows.sliceToPrefixedFileW(new_path);
2025 return renameatW(old_dir_fd, old_path_w.span(), new_dir_fd, new_path_w.span(), windows.TRUE);2025 return renameatW(old_dir_fd, old_path_w.span(), new_dir_fd, new_path_w.span(), windows.TRUE);
2026 } else if (builtin.os.tag == .wasi) {2026 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
2027 return renameatWasi(old_dir_fd, old_path, new_dir_fd, new_path);2027 return renameatWasi(old_dir_fd, old_path, new_dir_fd, new_path);
2028 } else {2028 } else {
2029 const old_path_c = try toPosixPath(old_path);2029 const old_path_c = try toPosixPath(old_path);
...@@ -2159,7 +2159,7 @@ pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!v...@@ -2159,7 +2159,7 @@ pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!v
2159 if (builtin.os.tag == .windows) {2159 if (builtin.os.tag == .windows) {
2160 const sub_dir_path_w = try windows.sliceToPrefixedFileW(sub_dir_path);2160 const sub_dir_path_w = try windows.sliceToPrefixedFileW(sub_dir_path);
2161 return mkdiratW(dir_fd, sub_dir_path_w.span(), mode);2161 return mkdiratW(dir_fd, sub_dir_path_w.span(), mode);
2162 } else if (builtin.os.tag == .wasi) {2162 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
2163 return mkdiratWasi(dir_fd, sub_dir_path, mode);2163 return mkdiratWasi(dir_fd, sub_dir_path, mode);
2164 } else {2164 } else {
2165 const sub_dir_path_c = try toPosixPath(sub_dir_path);2165 const sub_dir_path_c = try toPosixPath(sub_dir_path);
...@@ -2519,7 +2519,7 @@ pub fn readlinkZ(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8...@@ -2519,7 +2519,7 @@ pub fn readlinkZ(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8
2519/// The return value is a slice of `out_buffer` from index 0.2519/// The return value is a slice of `out_buffer` from index 0.
2520/// See also `readlinkatWasi`, `realinkatZ` and `realinkatW`.2520/// See also `readlinkatWasi`, `realinkatZ` and `realinkatW`.
2521pub fn readlinkat(dirfd: fd_t, file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {2521pub fn readlinkat(dirfd: fd_t, file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
2522 if (builtin.os.tag == .wasi) {2522 if (builtin.os.tag == .wasi and !builtin.link_libc) {
2523 return readlinkatWasi(dirfd, file_path, out_buffer);2523 return readlinkatWasi(dirfd, file_path, out_buffer);
2524 }2524 }
2525 if (builtin.os.tag == .windows) {2525 if (builtin.os.tag == .windows) {
...@@ -3481,7 +3481,7 @@ pub const FStatError = error{...@@ -3481,7 +3481,7 @@ pub const FStatError = error{
34813481
3482/// Return information about a file descriptor.3482/// Return information about a file descriptor.
3483pub fn fstat(fd: fd_t) FStatError!Stat {3483pub fn fstat(fd: fd_t) FStatError!Stat {
3484 if (builtin.os.tag == .wasi) {3484 if (builtin.os.tag == .wasi and !builtin.link_libc) {
3485 var stat: wasi.filestat_t = undefined;3485 var stat: wasi.filestat_t = undefined;
3486 switch (wasi.fd_filestat_get(fd, &stat)) {3486 switch (wasi.fd_filestat_get(fd, &stat)) {
3487 wasi.ESUCCESS => return Stat.fromFilestat(stat),3487 wasi.ESUCCESS => return Stat.fromFilestat(stat),
...@@ -3519,7 +3519,7 @@ pub const FStatAtError = FStatError || error{ NameTooLong, FileNotFound, SymLink...@@ -3519,7 +3519,7 @@ pub const FStatAtError = FStatError || error{ NameTooLong, FileNotFound, SymLink
3519/// which is relative to `dirfd` handle.3519/// which is relative to `dirfd` handle.
3520/// See also `fstatatZ` and `fstatatWasi`.3520/// See also `fstatatZ` and `fstatatWasi`.
3521pub fn fstatat(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!Stat {3521pub fn fstatat(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!Stat {
3522 if (builtin.os.tag == .wasi) {3522 if (builtin.os.tag == .wasi and !builtin.link_libc) {
3523 return fstatatWasi(dirfd, pathname, flags);3523 return fstatatWasi(dirfd, pathname, flags);
3524 } else if (builtin.os.tag == .windows) {3524 } else if (builtin.os.tag == .windows) {
3525 @compileError("fstatat is not yet implemented on Windows");3525 @compileError("fstatat is not yet implemented on Windows");
...@@ -4123,7 +4123,7 @@ pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {...@@ -4123,7 +4123,7 @@ pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {
4123 if (builtin.os.tag == .windows) {4123 if (builtin.os.tag == .windows) {
4124 return windows.SetFilePointerEx_BEGIN(fd, offset);4124 return windows.SetFilePointerEx_BEGIN(fd, offset);
4125 }4125 }
4126 if (builtin.os.tag == .wasi) {4126 if (builtin.os.tag == .wasi and !builtin.link_libc) {
4127 var new_offset: wasi.filesize_t = undefined;4127 var new_offset: wasi.filesize_t = undefined;
4128 switch (wasi.fd_seek(fd, @bitCast(wasi.filedelta_t, offset), wasi.WHENCE_SET, &new_offset)) {4128 switch (wasi.fd_seek(fd, @bitCast(wasi.filedelta_t, offset), wasi.WHENCE_SET, &new_offset)) {
4129 wasi.ESUCCESS => return,4129 wasi.ESUCCESS => return,
...@@ -4171,7 +4171,7 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {...@@ -4171,7 +4171,7 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {
4171 if (builtin.os.tag == .windows) {4171 if (builtin.os.tag == .windows) {
4172 return windows.SetFilePointerEx_CURRENT(fd, offset);4172 return windows.SetFilePointerEx_CURRENT(fd, offset);
4173 }4173 }
4174 if (builtin.os.tag == .wasi) {4174 if (builtin.os.tag == .wasi and !builtin.link_libc) {
4175 var new_offset: wasi.filesize_t = undefined;4175 var new_offset: wasi.filesize_t = undefined;
4176 switch (wasi.fd_seek(fd, offset, wasi.WHENCE_CUR, &new_offset)) {4176 switch (wasi.fd_seek(fd, offset, wasi.WHENCE_CUR, &new_offset)) {
4177 wasi.ESUCCESS => return,4177 wasi.ESUCCESS => return,
...@@ -4218,7 +4218,7 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {...@@ -4218,7 +4218,7 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {
4218 if (builtin.os.tag == .windows) {4218 if (builtin.os.tag == .windows) {
4219 return windows.SetFilePointerEx_END(fd, offset);4219 return windows.SetFilePointerEx_END(fd, offset);
4220 }4220 }
4221 if (builtin.os.tag == .wasi) {4221 if (builtin.os.tag == .wasi and !builtin.link_libc) {
4222 var new_offset: wasi.filesize_t = undefined;4222 var new_offset: wasi.filesize_t = undefined;
4223 switch (wasi.fd_seek(fd, offset, wasi.WHENCE_END, &new_offset)) {4223 switch (wasi.fd_seek(fd, offset, wasi.WHENCE_END, &new_offset)) {
4224 wasi.ESUCCESS => return,4224 wasi.ESUCCESS => return,
...@@ -4265,7 +4265,7 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {...@@ -4265,7 +4265,7 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {
4265 if (builtin.os.tag == .windows) {4265 if (builtin.os.tag == .windows) {
4266 return windows.SetFilePointerEx_CURRENT_get(fd);4266 return windows.SetFilePointerEx_CURRENT_get(fd);
4267 }4267 }
4268 if (builtin.os.tag == .wasi) {4268 if (builtin.os.tag == .wasi and !builtin.link_libc) {
4269 var new_offset: wasi.filesize_t = undefined;4269 var new_offset: wasi.filesize_t = undefined;
4270 switch (wasi.fd_seek(fd, 0, wasi.WHENCE_CUR, &new_offset)) {4270 switch (wasi.fd_seek(fd, 0, wasi.WHENCE_CUR, &new_offset)) {
4271 wasi.ESUCCESS => return new_offset,4271 wasi.ESUCCESS => return new_offset,
...@@ -4665,7 +4665,7 @@ pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError;...@@ -4665,7 +4665,7 @@ pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError;
4665/// TODO: change this to return the timespec as a return value4665/// TODO: change this to return the timespec as a return value
4666/// TODO: look into making clk_id an enum4666/// TODO: look into making clk_id an enum
4667pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void {4667pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void {
4668 if (std.Target.current.os.tag == .wasi) {4668 if (std.Target.current.os.tag == .wasi and !builtin.link_libc) {
4669 var ts: timestamp_t = undefined;4669 var ts: timestamp_t = undefined;
4670 switch (system.clock_time_get(@bitCast(u32, clk_id), 1, &ts)) {4670 switch (system.clock_time_get(@bitCast(u32, clk_id), 1, &ts)) {
4671 0 => {4671 0 => {
...@@ -4706,7 +4706,7 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void {...@@ -4706,7 +4706,7 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void {
4706}4706}
47074707
4708pub fn clock_getres(clk_id: i32, res: *timespec) ClockGetTimeError!void {4708pub fn clock_getres(clk_id: i32, res: *timespec) ClockGetTimeError!void {
4709 if (std.Target.current.os.tag == .wasi) {4709 if (std.Target.current.os.tag == .wasi and !builtin.link_libc) {
4710 var ts: timestamp_t = undefined;4710 var ts: timestamp_t = undefined;
4711 switch (system.clock_res_get(@bitCast(u32, clk_id), &ts)) {4711 switch (system.clock_res_get(@bitCast(u32, clk_id), &ts)) {
4712 0 => res.* = .{4712 0 => res.* = .{
...@@ -4834,7 +4834,7 @@ pub const FutimensError = error{...@@ -4834,7 +4834,7 @@ pub const FutimensError = error{
4834} || UnexpectedError;4834} || UnexpectedError;
48354835
4836pub fn futimens(fd: fd_t, times: *const [2]timespec) FutimensError!void {4836pub fn futimens(fd: fd_t, times: *const [2]timespec) FutimensError!void {
4837 if (builtin.os.tag == .wasi) {4837 if (builtin.os.tag == .wasi and !builtin.link_libc) {
4838 // TODO WASI encodes `wasi.fstflags` to signify magic values4838 // TODO WASI encodes `wasi.fstflags` to signify magic values
4839 // similar to UTIME_NOW and UTIME_OMIT. Currently, we ignore4839 // similar to UTIME_NOW and UTIME_OMIT. Currently, we ignore
4840 // this here, but we should really handle it somehow.4840 // this here, but we should really handle it somehow.
...@@ -5581,7 +5581,10 @@ var has_copy_file_range_syscall = std.atomic.Atomic(bool).init(true);...@@ -5581,7 +5581,10 @@ var has_copy_file_range_syscall = std.atomic.Atomic(bool).init(true);
5581///5581///
5582/// Maximum offsets on Linux are `math.maxInt(i64)`.5582/// Maximum offsets on Linux are `math.maxInt(i64)`.
5583pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len: usize, flags: u32) CopyFileRangeError!usize {5583pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len: usize, flags: u32) CopyFileRangeError!usize {
5584 const call_cfr = comptime if (builtin.link_libc)5584 const call_cfr = comptime if (std.Target.current.os.tag == .wasi)
5585 // WASI-libc doesn't have copy_file_range.
5586 false
5587 else if (builtin.link_libc)
5585 std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok5588 std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok
5586 else5589 else
5587 std.Target.current.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) orelse true;5590 std.Target.current.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) orelse true;
lib/std/os/bits/wasi.zig+55-8
...@@ -4,11 +4,13 @@...@@ -4,11 +4,13 @@
4// The MIT license requires this copyright notice to be included in all copies4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.5// and substantial portions of the software.
6// Convenience types and consts used by std.os module6// Convenience types and consts used by std.os module
7const builtin = @import("builtin");
8
7pub const STDIN_FILENO = 0;9pub const STDIN_FILENO = 0;
8pub const STDOUT_FILENO = 1;10pub const STDOUT_FILENO = 1;
9pub const STDERR_FILENO = 2;11pub const STDERR_FILENO = 2;
1012
11pub const mode_t = u0;13pub const mode_t = u32;
1214
13pub const time_t = i64; // match https://github.com/CraneStation/wasi-libc15pub const time_t = i64; // match https://github.com/CraneStation/wasi-libc
1416
...@@ -71,7 +73,8 @@ pub const kernel_stat = struct {...@@ -71,7 +73,8 @@ pub const kernel_stat = struct {
71 }73 }
72};74};
7375
74pub const AT_REMOVEDIR: u32 = 1; // there's no AT_REMOVEDIR in WASI, but we simulate here to match other OSes76pub const AT_REMOVEDIR: u32 = 0x4;
77pub const AT_FDCWD: fd_t = -2;
7578
76// As defined in the wasi_snapshot_preview1 spec file:79// As defined in the wasi_snapshot_preview1 spec file:
77// https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/typenames.witx80// https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/typenames.witx
...@@ -111,6 +114,7 @@ pub const EADDRINUSE: errno_t = 3;...@@ -111,6 +114,7 @@ pub const EADDRINUSE: errno_t = 3;
111pub const EADDRNOTAVAIL: errno_t = 4;114pub const EADDRNOTAVAIL: errno_t = 4;
112pub const EAFNOSUPPORT: errno_t = 5;115pub const EAFNOSUPPORT: errno_t = 5;
113pub const EAGAIN: errno_t = 6;116pub const EAGAIN: errno_t = 6;
117pub const EWOULDBLOCK = EAGAIN;
114pub const EALREADY: errno_t = 7;118pub const EALREADY: errno_t = 7;
115pub const EBADF: errno_t = 8;119pub const EBADF: errno_t = 8;
116pub const EBADMSG: errno_t = 9;120pub const EBADMSG: errno_t = 9;
...@@ -163,6 +167,7 @@ pub const ENOTEMPTY: errno_t = 55;...@@ -163,6 +167,7 @@ pub const ENOTEMPTY: errno_t = 55;
163pub const ENOTRECOVERABLE: errno_t = 56;167pub const ENOTRECOVERABLE: errno_t = 56;
164pub const ENOTSOCK: errno_t = 57;168pub const ENOTSOCK: errno_t = 57;
165pub const ENOTSUP: errno_t = 58;169pub const ENOTSUP: errno_t = 58;
170pub const EOPNOTSUPP = ENOTSUP;
166pub const ENOTTY: errno_t = 59;171pub const ENOTTY: errno_t = 59;
167pub const ENXIO: errno_t = 60;172pub const ENXIO: errno_t = 60;
168pub const EOVERFLOW: errno_t = 61;173pub const EOVERFLOW: errno_t = 61;
...@@ -204,7 +209,7 @@ pub const EVENTTYPE_FD_WRITE: eventtype_t = 2;...@@ -204,7 +209,7 @@ pub const EVENTTYPE_FD_WRITE: eventtype_t = 2;
204209
205pub const exitcode_t = u32;210pub const exitcode_t = u32;
206211
207pub const fd_t = u32;212pub const fd_t = if (builtin.link_libc) c_int else u32;
208213
209pub const fdflags_t = u16;214pub const fdflags_t = u16;
210pub const FDFLAG_APPEND: fdflags_t = 0x0001;215pub const FDFLAG_APPEND: fdflags_t = 0x0001;
...@@ -271,11 +276,33 @@ pub const linkcount_t = u64;...@@ -271,11 +276,33 @@ pub const linkcount_t = u64;
271pub const lookupflags_t = u32;276pub const lookupflags_t = u32;
272pub const LOOKUP_SYMLINK_FOLLOW: lookupflags_t = 0x00000001;277pub const LOOKUP_SYMLINK_FOLLOW: lookupflags_t = 0x00000001;
273278
274pub const oflags_t = u16;279pub usingnamespace if (builtin.link_libc) struct {
275pub const O_CREAT: oflags_t = 0x0001;280 pub const O_ACCMODE = (O_EXEC | O_RDWR | O_SEARCH);
276pub const O_DIRECTORY: oflags_t = 0x0002;281 pub const O_APPEND = 1 << 0; // = __WASI_FDFLAGS_APPEND
277pub const O_EXCL: oflags_t = 0x0004;282 pub const O_CLOEXEC = (0);
278pub const O_TRUNC: oflags_t = 0x0008;283 pub const O_CREAT = ((1 << 0) << 12); // = __WASI_OFLAGS_CREAT << 12
284 pub const O_DIRECTORY = ((1 << 1) << 12); // = __WASI_OFLAGS_DIRECTORY << 12
285 pub const O_DSYNC = (1 << 1); // = __WASI_FDFLAGS_DSYNC
286 pub const O_EXCL = ((1 << 2) << 12); // = __WASI_OFLAGS_EXCL << 12
287 pub const O_EXEC = (0x02000000);
288 pub const O_NOCTTY = (0);
289 pub const O_NOFOLLOW = (0x01000000);
290 pub const O_NONBLOCK = (1 << 2); // = __WASI_FDFLAGS_NONBLOCK
291 pub const O_RDONLY = (0x04000000);
292 pub const O_RDWR = (O_RDONLY | O_WRONLY);
293 pub const O_RSYNC = (1 << 3); // = __WASI_FDFLAGS_RSYNC
294 pub const O_SEARCH = (0x08000000);
295 pub const O_SYNC = (1 << 4); // = __WASI_FDFLAGS_SYNC
296 pub const O_TRUNC = ((1 << 3) << 12); // = __WASI_OFLAGS_TRUNC << 12
297 pub const O_TTY_INIT = (0);
298 pub const O_WRONLY = (0x10000000);
299} else struct {
300 pub const oflags_t = u16;
301 pub const O_CREAT: oflags_t = 0x0001;
302 pub const O_DIRECTORY: oflags_t = 0x0002;
303 pub const O_EXCL: oflags_t = 0x0004;
304 pub const O_TRUNC: oflags_t = 0x0008;
305};
279306
280pub const preopentype_t = u8;307pub const preopentype_t = u8;
281pub const PREOPENTYPE_DIR: preopentype_t = 0;308pub const PREOPENTYPE_DIR: preopentype_t = 0;
...@@ -437,3 +464,23 @@ pub const whence_t = u8;...@@ -437,3 +464,23 @@ pub const whence_t = u8;
437pub const WHENCE_SET: whence_t = 0;464pub const WHENCE_SET: whence_t = 0;
438pub const WHENCE_CUR: whence_t = 1;465pub const WHENCE_CUR: whence_t = 1;
439pub const WHENCE_END: whence_t = 2;466pub const WHENCE_END: whence_t = 2;
467
468pub const S_IEXEC = S_IXUSR;
469pub const S_IFBLK = 0x6000;
470pub const S_IFCHR = 0x2000;
471pub const S_IFDIR = 0x4000;
472pub const S_IFIFO = 0xc000;
473pub const S_IFLNK = 0xa000;
474pub const S_IFMT = S_IFBLK | S_IFCHR | S_IFDIR | S_IFIFO | S_IFLNK | S_IFREG | S_IFSOCK;
475pub const S_IFREG = 0x8000;
476// There's no concept of UNIX domain socket but we define this value here in order to line with other OSes.
477pub const S_IFSOCK = 0x1;
478
479pub const SEEK_SET = 0x0; // = __WASI_WHENCE_SET
480pub const SEEK_CUR = 0x1; // = __WASI_WHENCE_CUR
481pub const SEEK_END = 0x2; // = __WASI_WHENCE_END
482
483pub const LOCK_SH = 0x1;
484pub const LOCK_EX = 0x2;
485pub const LOCK_NB = 0x4;
486pub const LOCK_UN = 0x8;
lib/std/process.zig+4-4
...@@ -88,7 +88,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {...@@ -88,7 +88,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
88 try result.putMove(key, value);88 try result.putMove(key, value);
89 }89 }
90 return result;90 return result;
91 } else if (builtin.os.tag == .wasi) {91 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
92 var environ_count: usize = undefined;92 var environ_count: usize = undefined;
93 var environ_buf_size: usize = undefined;93 var environ_buf_size: usize = undefined;
9494
...@@ -450,7 +450,7 @@ pub const ArgIteratorWindows = struct {...@@ -450,7 +450,7 @@ pub const ArgIteratorWindows = struct {
450pub const ArgIterator = struct {450pub const ArgIterator = struct {
451 const InnerType = switch (builtin.os.tag) {451 const InnerType = switch (builtin.os.tag) {
452 .windows => ArgIteratorWindows,452 .windows => ArgIteratorWindows,
453 .wasi => ArgIteratorWasi,453 .wasi => if (builtin.link_libc) ArgIteratorPosix else ArgIteratorWasi,
454 else => ArgIteratorPosix,454 else => ArgIteratorPosix,
455 };455 };
456456
...@@ -469,7 +469,7 @@ pub const ArgIterator = struct {...@@ -469,7 +469,7 @@ pub const ArgIterator = struct {
469469
470 /// You must deinitialize iterator's internal buffers by calling `deinit` when done.470 /// You must deinitialize iterator's internal buffers by calling `deinit` when done.
471 pub fn initWithAllocator(allocator: *mem.Allocator) InitError!ArgIterator {471 pub fn initWithAllocator(allocator: *mem.Allocator) InitError!ArgIterator {
472 if (builtin.os.tag == .wasi) {472 if (builtin.os.tag == .wasi and !builtin.link_libc) {
473 return ArgIterator{ .inner = try InnerType.init(allocator) };473 return ArgIterator{ .inner = try InnerType.init(allocator) };
474 }474 }
475475
...@@ -507,7 +507,7 @@ pub const ArgIterator = struct {...@@ -507,7 +507,7 @@ pub const ArgIterator = struct {
507 /// was created with `initWithAllocator` function.507 /// was created with `initWithAllocator` function.
508 pub fn deinit(self: *ArgIterator) void {508 pub fn deinit(self: *ArgIterator) void {
509 // Unless we're targeting WASI, this is a no-op.509 // Unless we're targeting WASI, this is a no-op.
510 if (builtin.os.tag == .wasi) {510 if (builtin.os.tag == .wasi and !builtin.link_libc) {
511 self.inner.deinit();511 self.inner.deinit();
512 }512 }
513 }513 }
lib/std/start.zig+8-1
...@@ -46,7 +46,9 @@ comptime {...@@ -46,7 +46,9 @@ comptime {
46 }46 }
47 } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) {47 } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) {
48 if (builtin.link_libc and @hasDecl(root, "main")) {48 if (builtin.link_libc and @hasDecl(root, "main")) {
49 if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {49 if (native_arch.isWasm()) {
50 @export(mainWithoutEnv, .{ .name = "main" });
51 } else if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {
50 @export(main, .{ .name = "main" });52 @export(main, .{ .name = "main" });
51 }53 }
52 } else if (native_os == .windows) {54 } else if (native_os == .windows) {
...@@ -420,6 +422,11 @@ fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C)...@@ -420,6 +422,11 @@ fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C)
420 return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp });422 return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp });
421}423}
422424
425fn mainWithoutEnv(c_argc: i32, c_argv: [*][*:0]u8) callconv(.C) usize {
426 std.os.argv = c_argv[0..@intCast(usize, c_argc)];
427 return @call(.{ .modifier = .always_inline }, callMain, .{});
428}
429
423// General error message for a malformed return type430// General error message for a malformed return type
424const bad_main_ret = "expected return type of main to be 'void', '!void', 'noreturn', 'u8', or '!u8'";431const bad_main_ret = "expected return type of main to be 'void', '!void', 'noreturn', 'u8', or '!u8'";
425432
lib/std/testing.zig+3-1
...@@ -4,6 +4,8 @@...@@ -4,6 +4,8 @@
4// The MIT license requires this copyright notice to be included in all copies4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.5// and substantial portions of the software.
6const std = @import("std.zig");6const std = @import("std.zig");
7const builtin = @import("builtin");
8
7const math = std.math;9const math = std.math;
8const print = std.debug.print;10const print = std.debug.print;
911
...@@ -326,7 +328,7 @@ pub const TmpDir = struct {...@@ -326,7 +328,7 @@ pub const TmpDir = struct {
326};328};
327329
328fn getCwdOrWasiPreopen() std.fs.Dir {330fn getCwdOrWasiPreopen() std.fs.Dir {
329 if (std.builtin.os.tag == .wasi) {331 if (std.builtin.os.tag == .wasi and !builtin.link_libc) {
330 var preopens = std.fs.wasi.PreopenList.init(allocator);332 var preopens = std.fs.wasi.PreopenList.init(allocator);
331 defer preopens.deinit();333 defer preopens.deinit();
332 preopens.populate() catch334 preopens.populate() catch
src/stage1/codegen.cpp+3-1
...@@ -582,7 +582,9 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {...@@ -582,7 +582,9 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
582582
583 bool want_ssp_attrs = g->build_mode != BuildModeFastRelease &&583 bool want_ssp_attrs = g->build_mode != BuildModeFastRelease &&
584 g->build_mode != BuildModeSmallRelease &&584 g->build_mode != BuildModeSmallRelease &&
585 g->link_libc;585 g->link_libc &&
586 // WASI-libc does not support stack-protector yet.
587 !target_is_wasm(g->zig_target);
586 if (want_ssp_attrs) {588 if (want_ssp_attrs) {
587 addLLVMFnAttr(llvm_fn, "sspstrong");589 addLLVMFnAttr(llvm_fn, "sspstrong");
588 addLLVMFnAttrStr(llvm_fn, "stack-protector-buffer-size", "4");590 addLLVMFnAttrStr(llvm_fn, "stack-protector-buffer-size", "4");
test/cases.zig+1-1
...@@ -26,7 +26,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -26,7 +26,7 @@ pub fn addCases(ctx: *TestContext) !void {
26 var case = ctx.exe("hello world with updates", linux_x64);26 var case = ctx.exe("hello world with updates", linux_x64);
2727
28 case.addError("", &[_][]const u8{28 case.addError("", &[_][]const u8{
29 ":93:9: error: struct 'tmp.tmp' has no member named 'main'",29 ":95:9: error: struct 'tmp.tmp' has no member named 'main'",
30 });30 });
3131
32 // Incorrect return type32 // Incorrect return type
test/stage2/darwin.zig+1-1
...@@ -14,7 +14,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -14,7 +14,7 @@ pub fn addCases(ctx: *TestContext) !void {
14 {14 {
15 var case = ctx.exe("hello world with updates", target);15 var case = ctx.exe("hello world with updates", target);
16 case.addError("", &[_][]const u8{16 case.addError("", &[_][]const u8{
17 ":93:9: error: struct 'tmp.tmp' has no member named 'main'",17 ":95:9: error: struct 'tmp.tmp' has no member named 'main'",
18 });18 });
1919
20 // Incorrect return type20 // Incorrect return type
test/tests.zig+8
...@@ -57,6 +57,14 @@ const test_targets = blk: {...@@ -57,6 +57,14 @@ const test_targets = blk: {
57 .link_libc = false,57 .link_libc = false,
58 .single_threaded = true,58 .single_threaded = true,
59 },59 },
60 TestTarget{
61 .target = .{
62 .cpu_arch = .wasm32,
63 .os_tag = .wasi,
64 },
65 .link_libc = true,
66 .single_threaded = true,
67 },
6068
61 TestTarget{69 TestTarget{
62 .target = .{70 .target = .{