commit 71a460aebe99b38eea5923a6aed9aea8e1eda10b
parent e5c234e3ff6bba4530951d4dcc2efc525a6961f2
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 24 Oct 2021 13:29:16 +0200
rt: initial +freebsd support
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
54 files changed, 5546 insertions(+), 745 deletions(-)
diff --git a/Makefile b/Makefile
@@ -41,7 +41,7 @@ haredoc_srcs=\
./cmd/haredoc/sort.ha \
./cmd/haredoc/resolver.ha
-$(HARECACHE)/hare.ssa: $(hare_srcs) $(hare_stdlib_deps)
+$(HARECACHE)/hare.ssa: $(hare_srcs) $(stdlib_deps_any) $(stdlib_deps_$(PLATFORM))
@printf 'HAREC\t$@\n'
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) \
-D PLATFORM:str='"'"$$(./scripts/platform)"'"' \
@@ -49,7 +49,7 @@ $(HARECACHE)/hare.ssa: $(hare_srcs) $(hare_stdlib_deps)
-D HAREPATH:str='"'"$(HAREPATH)"'"' \
-o $@ $(hare_srcs)
-$(TESTCACHE)/hare.ssa: $(hare_srcs) $(hare_testlib_deps)
+$(TESTCACHE)/hare.ssa: $(hare_srcs) $(testlib_deps_any) $(testlib_deps_$(PLATFORM))
@printf 'HAREC\t$@\n'
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) \
-D PLATFORM:str='"'"$$(./scripts/platform)"'"' \
@@ -61,13 +61,13 @@ $(TESTCACHE)/hare.ssa: $(hare_srcs) $(hare_testlib_deps)
@mkdir -p .bin
@printf 'LD\t$@\n'
@$(LD) --gc-sections -T $(rtscript) -o $@ \
- $(HARECACHE)/hare.o $(hare_stdlib_deps)
+ $(HARECACHE)/hare.o $(stdlib_deps_any) $(stdlib_deps_$(PLATFORM))
.bin/hare-tests: $(TESTCACHE)/hare.o
@mkdir -p .bin
@printf 'LD\t$@\n'
@$(LD) -T $(rtscript) -o $@ \
- $(TESTCACHE)/hare.o $(hare_testlib_deps)
+ $(TESTCACHE)/hare.o $(testlib_deps_any) $(testlib_deps_$(PLATFORM))
.bin/harec: .bin/hare $(harec_srcs)
@mkdir -p .bin
diff --git a/cmd/hare/main.ha b/cmd/hare/main.ha
@@ -1,5 +1,6 @@
use getopt;
use os;
+use fmt;
def VERSION: str = "unknown";
def PLATFORM: str = "unknown";
diff --git a/crypto/random/+freebsd.ha b/crypto/random/+freebsd.ha
@@ -0,0 +1,33 @@
+use errors;
+use rt;
+use io;
+
+// Fills the given buffer with cryptographically random data. If the system is
+// unable to provide random data, abort. If you need to handle errors or want to
+// use whatever random data the system can provide, even if less than the
+// requested amont, use [[stream]] instead.
+export fn buffer(buf: []u8) void = {
+ let n = 0z;
+ for (n < len(buf)) {
+ match (rt::getrandom(buf[n..]: *[*]u8, len(buf), 0)) {
+ case err: rt::errno =>
+ switch (err) {
+ case rt::EINTR => void;
+ case =>
+ abort();
+ };
+ case z: size =>
+ n += z;
+ };
+ };
+};
+
+fn rand_reader(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = {
+ assert(s == stream);
+ match (rt::getrandom(buf: *[*]u8, len(buf), 0)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case n: size =>
+ return n;
+ };
+};
diff --git a/format/elf/+freebsd.ha b/format/elf/+freebsd.ha
@@ -0,0 +1,2 @@
+// The ABI of the target.
+export def TARGET_ABI: ident_abi = ident_abi::SYSV;
diff --git a/hare/module/scan.ha b/hare/module/scan.ha
@@ -164,6 +164,7 @@ fn scan_directory(
append(dirs, strings::dup(ent.name));
case fs::mode::REG =>
append(files, strings::dup(ent.name));
+ case => abort();
};
};
diff --git a/io/+freebsd/file.ha b/io/+freebsd/file.ha
@@ -0,0 +1,59 @@
+use errors;
+use rt;
+use strings;
+
+// This is an opaque type which encloses an OS-level file handle resource (on
+// Unix, a file descriptor, or "fd") within a stream. It can be used as an
+// [[stream]] in most situations, but there are some APIs which require an
+// [[file]] with some OS-level handle backing it - this type is used for such
+// APIs.
+export type file = int;
+
+// Opens a Unix file descriptor as a file. This is a low-level interface, to
+// open files most programs will use something like [[os::open]]. This function
+// is not portable.
+export fn fdopen(fd: int) file = fd;
+
+fn fd_read(fd: file, buf: []u8) (size | EOF | error) = {
+ match (rt::read(fd, buf: *[*]u8, len(buf))) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case n: size =>
+ switch (n) {
+ case 0 =>
+ return EOF;
+ case =>
+ return n;
+ };
+ };
+};
+
+fn fd_write(fd: file, buf: const []u8) (size | error) = {
+ match (rt::write(fd, buf: *const [*]u8, len(buf))) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case n: size =>
+ return n;
+ };
+};
+
+fn fd_close(fd: file) void = rt::close(fd)!;
+
+fn fd_seek(
+ fd: file,
+ off: off,
+ whence: whence,
+) (off | error) = {
+ match (rt::lseek(fd, off: i64, whence: uint)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case n: i64 =>
+ return n: off;
+ };
+};
+
+def SENDFILE_MAX: size = 2147479552z;
+
+fn fd_copy(to: file, from: file) (size | error) = {
+ abort(); // TODO: FreeBSD
+};
diff --git a/io/println+freebsd.ha b/io/println+freebsd.ha
@@ -0,0 +1,35 @@
+use rt;
+
+// Prints strings to stdout, separated by spaces, and followed by a newline.
+//
+// The output is unbuffered, and may not have good performance. This is only
+// recommended for debugging purposes. See [[fmt::println]] instead.
+export fn println(msgs: str...) void = {
+ for (let i = 0z; i < len(msgs); i += 1) {
+ let msg = msgs[i];
+ rt::write(1, *(&msg: **void): *const char, len(msg)): void;
+ if (i + 1 < len(msgs)) {
+ const sp = " ";
+ rt::write(1, *(&sp: **void): *const char, 1): void;
+ };
+ };
+ const linefeed = "\n";
+ rt::write(1, *(&linefeed: **void): *const char, 1): void;
+};
+
+// Prints strings to stderr, separated by spaces, and followed by a newline.
+//
+// The output is unbuffered, and may not have good performance. This is only
+// recommended for debugging purposes. See [[fmt::errorln]] instead.
+export fn errorln(msgs: str...) void = {
+ for (let i = 0z; i < len(msgs); i += 1) {
+ let msg = msgs[i];
+ rt::write(2, *(&msg: **void): *const char, len(msg)): void;
+ if (i + 1 < len(msgs)) {
+ const sp = " ";
+ rt::write(2, *(&sp: **void): *const char, 1): void;
+ };
+ };
+ const linefeed = "\n";
+ rt::write(2, *(&linefeed: **void): *const char, 1): void;
+};
diff --git a/net/+freebsd.ha b/net/+freebsd.ha
@@ -0,0 +1,41 @@
+// Some common code for handling sockets on +freebsd
+use errors;
+use fmt;
+use io;
+use net::ip;
+use os;
+use rt;
+use strings;
+
+export type stream_listener = struct {
+ l: listener,
+ fd: int,
+};
+
+// Gets the fd of the listener's socket. This function is not portable.
+export fn listenerfd(l: *listener) (io::file | void) = {
+ if (l.accept == &stream_accept) {
+ return (l: *stream_listener).fd;
+ };
+};
+
+export fn stream_accept(l: *listener) (io::file | error) = {
+ assert(l.accept == &stream_accept);
+ let l = l: *stream_listener;
+ let sn = rt::sockaddr {...};
+ const sz = size(rt::sockaddr): u32;
+ const fd = match (rt::accept(l.fd, &sn, &sz)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case fd: int =>
+ yield fd;
+ };
+ return io::fdopen(fd);
+};
+
+export fn stream_shutdown(l: *listener) void = {
+ assert(l.shutdown == &stream_shutdown);
+ let l = l: *stream_listener;
+ rt::close(l.fd)!;
+ free(l);
+};
diff --git a/net/ip/+freebsd.ha b/net/ip/+freebsd.ha
@@ -0,0 +1,50 @@
+use rt;
+use endian;
+
+export fn to_native(a: addr, port: u16) rt::sockaddr = {
+ match (a) {
+ case v4: addr4 =>
+ return rt::sockaddr { in = rt::sockaddr_in {
+ sin_len = size(rt::in_addr): u8,
+ sin_family = rt::AF_INET,
+ sin_port = endian::htonu16(port),
+ sin_addr = rt::in_addr { s_addr = *(&v4[0]: *void: *u32) },
+ } };
+ case v6: addr6 =>
+ return rt::sockaddr { in6 = rt::sockaddr_in6 {
+ sin6_len = size(rt::in6_addr): u8,
+ sin6_family = rt::AF_INET6,
+ sin6_port = endian::htonu16(port),
+ sin6_addr = rt::in6_addr { s6_addr = v6 },
+ } };
+ };
+};
+
+export fn from_native(a: rt::sockaddr) (addr, u16) = {
+ let family = a.in.sin_family;
+ switch (family) {
+ case rt::AF_INET =>
+ let addr = a.in.sin_addr.s_addr;
+ return (
+ [addr: u8, (addr >> 8): u8, (addr >> 16): u8,
+ (addr >> 24): u8]: addr4,
+ endian::ntohu16(a.in.sin_port)
+ );
+ case rt::AF_INET6 =>
+ return (
+ a.in6.sin6_addr.s6_addr: addr6,
+ endian::ntohu16(a.in6.sin6_port)
+ );
+ case =>
+ abort("Wrong address family!");
+ };
+};
+
+export fn native_addrlen(a: addr) u32 = {
+ match (a) {
+ case addr4 =>
+ return size(rt::sockaddr_in): u32;
+ case addr6 =>
+ return size(rt::sockaddr_in6): u32;
+ };
+};
diff --git a/net/tcp/+freebsd.ha b/net/tcp/+freebsd.ha
@@ -0,0 +1,143 @@
+use errors;
+use io;
+use net::ip;
+use net;
+use os;
+use rt;
+
+// Opens a TCP connection to the given host and port. Blocks until the
+// connection is established.
+export fn connect(
+ addr: ip::addr,
+ port: u16,
+ options: connect_option...
+) (io::file | net::error) = {
+ const sockaddr = ip::to_native(addr, port);
+ const family = match (addr) {
+ case ip::addr4 =>
+ yield rt::AF_INET: int;
+ case ip::addr6 =>
+ yield rt::AF_INET6: int;
+ };
+ const sockfd = match (rt::socket(family, rt::SOCK_STREAM, 0)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case fd: int =>
+ yield fd;
+ };
+ let flags = rt::fcntl(sockfd, rt::F_GETFL, 0)!;
+ rt::fcntl(sockfd, rt::F_SETFL, flags | rt::O_CLOEXEC)!;
+
+ for (let i = 0z; i < len(options); i += 1) {
+ // The only option is keepalive right now
+ setsockopt(sockfd, rt::SO_KEEPALIVE, true)?;
+ };
+ const sz = ip::native_addrlen(addr);
+ match (rt::connect(sockfd, &sockaddr, sz)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
+ };
+ return io::fdopen(sockfd);
+};
+
+// Binds a TCP listener to the given address.
+export fn listen(
+ addr: ip::addr,
+ port: u16,
+ options: listen_option...
+) (*net::listener | net::error) = {
+ const sockaddr = ip::to_native(addr, port);
+ const family = match (addr) {
+ case ip::addr4 =>
+ yield rt::AF_INET: int;
+ case ip::addr6 =>
+ yield rt::AF_INET6: int;
+ };
+ const sockfd = match (rt::socket(family, rt::SOCK_STREAM, 0)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case fd: int =>
+ yield fd;
+ };
+ let flags = rt::fcntl(sockfd, rt::F_GETFL, 0)!;
+ rt::fcntl(sockfd, rt::F_SETFL, flags | rt::O_CLOEXEC)!;
+
+ let bk: u32 = 10;
+ for (let i = 0z; i < len(options); i += 1) {
+ match (options[i]) {
+ case reuseaddr =>
+ setsockopt(sockfd, rt::SO_REUSEADDR, true)?;
+ case reuseport =>
+ setsockopt(sockfd, rt::SO_REUSEPORT, true)?;
+ case keepalive =>
+ setsockopt(sockfd, rt::SO_KEEPALIVE, true)?;
+ case b: backlog =>
+ bk = b;
+ case p: portassignment => void;
+ };
+ };
+
+ const sz = ip::native_addrlen(addr);
+ match (rt::bind(sockfd, &sockaddr, sz)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
+ };
+ match (rt::listen(sockfd, bk)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
+ };
+
+ for (let i = 0z; i < len(options); i += 1) {
+ let portout = match (options[i]) {
+ case p: portassignment =>
+ yield p;
+ case =>
+ continue;
+ };
+ let sn = rt::sockaddr {...};
+ let al = size(rt::sockaddr): u32;
+ match (rt::getsockname(sockfd, &sn, &al)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
+ };
+ const addr = ip::from_native(sn);
+ *portout = addr.1;
+ };
+
+ return alloc(net::stream_listener {
+ l = net::listener {
+ accept = &net::stream_accept,
+ shutdown = &net::stream_shutdown,
+ },
+ fd = sockfd,
+ }): *net::listener;
+};
+
+// Returns the remote address for a given connection, or void if none is
+// available.
+export fn peeraddr(peer: io::file) ((ip::addr, u16) | void) = {
+ let sn = rt::sockaddr {...};
+ let sz = size(rt::sockaddr): u32;
+ if (rt::getpeername(peer, &sn, &sz) is rt::errno) {
+ return;
+ };
+ return ip::from_native(sn);
+};
+
+fn setsockopt(
+ sockfd: int,
+ option: int,
+ value: bool,
+) (void | net::error) = {
+ let val: int = if (value) 1 else 0;
+ match (rt::setsockopt(sockfd, rt::SOL_SOCKET, option,
+ &val: *void, size(int): u32)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
+ };
+};
diff --git a/net/udp/+freebsd.ha b/net/udp/+freebsd.ha
@@ -0,0 +1,139 @@
+use errors;
+use io;
+use net::ip;
+use net;
+use os;
+use rt;
+
+// Creates a UDP socket and sets the default destination to the given address.
+export fn connect(
+ dest: ip::addr,
+ port: u16,
+) (io::file | net::error) = {
+ const family = match (dest) {
+ case ip::addr4 =>
+ yield rt::AF_INET: int;
+ case ip::addr6 =>
+ yield rt::AF_INET6: int;
+ };
+ const sockfd = match (rt::socket(family, rt::SOCK_DGRAM, 0)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case fd: int =>
+ yield fd;
+ };
+
+ const sockaddr = ip::to_native(dest, port);
+ const sz = ip::native_addrlen(dest);
+ match (rt::connect(sockfd, &sockaddr, sz)) {
+ case int =>
+ return io::fdopen(sockfd);
+ case err: rt::errno =>
+ return errors::errno(err);
+ };
+};
+
+// Creates a UDP socket bound to an interface.
+export fn listen(
+ addr: ip::addr,
+ port: u16,
+ options: listen_option...
+) (io::file | net::error) = {
+ const family = match (addr) {
+ case ip::addr4 =>
+ yield rt::AF_INET: int;
+ case ip::addr6 =>
+ yield rt::AF_INET6: int;
+ };
+ const sockfd = match (rt::socket(family, rt::SOCK_DGRAM, 0)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case fd: int =>
+ yield fd;
+ };
+ let flags = rt::fcntl(sockfd, rt::F_GETFL, 0)!;
+ rt::fcntl(sockfd, rt::F_SETFL, flags | rt::O_CLOEXEC)!;
+
+ const sockaddr = ip::to_native(addr, port);
+ const sz = ip::native_addrlen(addr);
+ match (rt::bind(sockfd, &sockaddr, sz)) {
+ case int => void;
+ case err: rt::errno =>
+ return errors::errno(err);
+ };
+
+ for (let i = 0z; i < len(options); i += 1) {
+ // The only option is portassignment right now
+ let sn = rt::sockaddr {...};
+ let al = size(rt::sockaddr): u32;
+ match (rt::getsockname(sockfd, &sn, &al)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
+ };
+ const addr = ip::from_native(sn);
+ *options[i] = addr.1;
+ };
+
+ return io::fdopen(sockfd);
+};
+
+// Sends a UDP packet to the destination previously specified by [[connect]].
+export fn send(sock: io::file, buf: []u8) (size | net::error) = {
+ match (rt::send(sock, buf: *[*]u8, len(buf), 0)) {
+ case sz: size =>
+ return sz;
+ case err: rt::errno =>
+ return errors::errno(err);
+ };
+};
+
+// Sends a UDP packet using this socket.
+export fn sendto(
+ sock: io::file,
+ buf: []u8,
+ dest: ip::addr,
+ port: u16,
+) (size | net::error) = {
+ const sockaddr = ip::to_native(dest, port);
+ const sz = ip::native_addrlen(dest);
+ match (rt::sendto(sock, buf: *[*]u8, len(buf), 0, &sockaddr, sz)) {
+ case sz: size =>
+ return sz;
+ case err: rt::errno =>
+ return errors::errno(err);
+ };
+};
+
+// Receives a UDP packet from a bound socket.
+export fn recvfrom(
+ sock: io::file,
+ buf: []u8,
+ src: nullable *ip::addr,
+ port: nullable *u16,
+) (size | net::error) = {
+ let addrsz = size(rt::sockaddr): u32;
+ const sockaddr = rt::sockaddr { ... };
+ const sz = match (rt::recvfrom(sock, buf: *[*]u8, len(buf), 0,
+ &sockaddr, &addrsz)) {
+ case sz: size =>
+ yield sz;
+ case err: rt::errno =>
+ return errors::errno(err);
+ };
+
+ assert(addrsz <= size(rt::sockaddr));
+ const peer = ip::from_native(sockaddr);
+ match (src) {
+ case null => void;
+ case src: *ip::addr =>
+ *src = peer.0;
+ };
+ match (port) {
+ case null => void;
+ case port: *u16 =>
+ *port = peer.1;
+ };
+
+ return sz;
+};
diff --git a/net/unix/+freebsd.ha b/net/unix/+freebsd.ha
@@ -0,0 +1,104 @@
+use errors;
+use fmt;
+use io;
+use net;
+use os;
+use rt;
+use strings;
+use types;
+
+// Opens a UNIX socket connection to the path. Blocks until the connection is
+// established.
+export fn connect(addr: addr) (io::file | net::error) = {
+ let sockaddr = match (to_native(addr)) {
+ case a: rt::sockaddr =>
+ yield a;
+ case invalid =>
+ return errors::unsupported; // path too long
+ };
+ const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM, 0)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case fd: int =>
+ yield fd;
+ };
+ let flags = rt::fcntl(sockfd, rt::F_GETFL, 0)!;
+ rt::fcntl(sockfd, rt::F_SETFL, flags | rt::O_CLOEXEC)!;
+
+ const sz = size(rt::sockaddr_un): u32;
+ match (rt::connect(sockfd, &sockaddr, sz)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
+ };
+ static let buf: [rt::UNIX_PATH_MAX + 32]u8 = [0...];
+ return io::fdopen(sockfd);
+};
+
+// Binds a UNIX socket listener to the given path.
+export fn listen(
+ addr: addr,
+ options: listen_option...
+) (*net::listener | net::error) = {
+ let sockaddr = match (to_native(addr)) {
+ case a: rt::sockaddr =>
+ yield a;
+ case invalid =>
+ return errors::unsupported; // path too long
+ };
+ const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM, 0)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case fd: int =>
+ yield fd;
+ };
+ let flags = rt::fcntl(sockfd, rt::F_GETFL, 0)!;
+ rt::fcntl(sockfd, rt::F_SETFL, flags | rt::O_CLOEXEC)!;
+
+ let bk: u32 = 10;
+ for (let i = 0z; i < len(options); i += 1) {
+ // Only option is backlog right now
+ bk = options[i];
+ };
+
+ match (rt::bind(sockfd, &sockaddr, size(rt::sockaddr_un): u32)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
+ };
+ match (rt::listen(sockfd, bk)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
+ };
+
+ return alloc(net::stream_listener {
+ l = net::listener {
+ accept = &net::stream_accept,
+ shutdown = &net::stream_shutdown,
+ },
+ fd = sockfd,
+ }): *net::listener;
+};
+
+// Converts a UNIX socket address to a native sockaddr.
+fn to_native(addr: addr) (rt::sockaddr | invalid) = {
+ // sun_path should be null-terminated and fit into rt::UNIX_PATH_MAX
+ if (len(addr) > rt::UNIX_PATH_MAX - 1) {
+ return invalid;
+ };
+ let ret = rt::sockaddr {
+ un = rt::sockaddr_un {
+ sun_len = size(rt::sockaddr_un): u8,
+ sun_family = rt::AF_UNIX,
+ ...
+ }
+ };
+ match ((&addr: *types::string).data) {
+ case null => void;
+ case data: *[*]u8 =>
+ rt::memcpy(&ret.un.sun_path, data, len(addr));
+ };
+ ret.un.sun_path[len(addr)] = 0;
+ return ret;
+};
diff --git a/os/+freebsd/dirfdfs.ha b/os/+freebsd/dirfdfs.ha
@@ -0,0 +1,459 @@
+use bytes;
+use errors;
+use encoding::utf8;
+use fs;
+use io;
+use path;
+use rt;
+use strings;
+use time;
+
+type os_filesystem = struct {
+ fs: fs::fs,
+ dirfd: int,
+ getdents_bufsz: size,
+};
+
+// Opens a file descriptor as an [[fs::fs]]. This file descriptor must be a
+// directory file. The file will be closed when the fs is closed.
+//
+// If no other flags are provided to [[fs::open]] and [[fs::create]] when used with
+// a dirfdfs, [[fs::flags::NOCTTY]] and [[fs::flags::CLOEXEC]] are used when opening
+// the file. If you pass your own flags, it is recommended that you add these
+// unless you know that you do not want them.
+export fn dirfdopen(fd: io::file) *fs::fs = {
+ let ofs = alloc(os_filesystem { ... });
+ let fs = static_dirfdopen(fd, ofs);
+ fs.close = &fs_close;
+ return fs;
+};
+
+fn static_dirfdopen(fd: io::file, filesystem: *os_filesystem) *fs::fs = {
+ *filesystem = os_filesystem {
+ fs = fs::fs {
+ open = &fs_open,
+ openfile = &fs_open_file,
+ create = &fs_create,
+ createfile = &fs_create_file,
+ remove = &fs_remove,
+ rename = &fs_rename,
+ iter = &fs_iter,
+ stat = &fs_stat,
+ readlink = &fs_readlink,
+ subdir = &fs_subdir,
+ mkdir = &fs_mkdir,
+ rmdir = &fs_rmdir,
+ chmod = &fs_chmod,
+ chown = &fs_chown,
+ resolve = &fs_resolve,
+ ...
+ },
+ dirfd = fd,
+ getdents_bufsz = 32768, // 32 KiB
+ };
+ return &filesystem.fs;
+};
+
+// Sets the buffer size to use with the getdents(2) system call, for use with
+// [[fs::iter]]. A larger buffer requires a larger runtime allocation, but can
+// scan large directories faster. The default buffer size is 32 KiB.
+//
+// This function is not portable.
+export fn dirfdfs_set_getdents_bufsz(fs: *fs::fs, sz: size) void = {
+ assert(fs.open == &fs_open);
+ let fs = fs: *os_filesystem;
+ fs.getdents_bufsz = sz;
+};
+
+// Returns an [[io::file]] for this filesystem. This function is not portable.
+export fn dirfile(fs: *fs::fs) io::file = {
+ assert(fs.open == &fs_open);
+ let fs = fs: *os_filesystem;
+ return fs.dirfd;
+};
+
+fn errno_to_fs(err: rt::errno) fs::error = switch (err) {
+case rt::ENOENT =>
+ yield errors::noentry;
+case rt::EEXIST =>
+ yield errors::exists;
+case rt::EACCES =>
+ yield errors::noaccess;
+case rt::EBUSY =>
+ yield errors::busy;
+case rt::ENOTDIR =>
+ yield fs::wrongtype;
+case rt::EOPNOTSUPP, rt::ENOSYS =>
+ yield errors::unsupported;
+case rt::EXDEV =>
+ yield fs::cannotrename;
+case =>
+ yield errors::errno(err);
+};
+
+fn _fs_open(
+ fs: *fs::fs,
+ path: str,
+ flags: int,
+ mode: uint,
+) (io::file | fs::error) = {
+ let fs = fs: *os_filesystem;
+
+ let fd = match (rt::openat(fs.dirfd, path, flags, mode)) {
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case fd: int =>
+ yield fd;
+ };
+
+ return io::fdopen(fd);
+};
+
+fn fsflags_to_bsd(flags: fs::flags) int = {
+ let out = 0;
+ if (flags & fs::flags::WRONLY > 0) {
+ out |= rt::O_WRONLY;
+ };
+ if (flags & fs::flags::RDWR > 0) {
+ out |= rt::O_RDWR;
+ };
+ if (flags & fs::flags::CREATE > 0) {
+ out |= rt::O_CREAT;
+ };
+ if (flags & fs::flags::EXCL > 0) {
+ out |= rt::O_EXCL;
+ };
+ if (flags & fs::flags::NOCTTY > 0) {
+ out |= rt::O_NOCTTY;
+ };
+ if (flags & fs::flags::TRUNC > 0) {
+ out |= rt::O_TRUNC;
+ };
+ if (flags & fs::flags::APPEND > 0) {
+ out |= rt::O_APPEND;
+ };
+ if (flags & fs::flags::NONBLOCK > 0) {
+ out |= rt::O_NONBLOCK;
+ };
+ if (flags & fs::flags::DSYNC > 0) {
+ out |= rt::O_DSYNC;
+ };
+ if (flags & fs::flags::SYNC > 0) {
+ out |= rt::O_SYNC;
+ };
+ if (flags & fs::flags::RSYNC > 0) {
+ out |= rt::O_SYNC;
+ };
+ if (flags & fs::flags::DIRECTORY > 0) {
+ out |= rt::O_DIRECTORY;
+ };
+ if (flags & fs::flags::NOFOLLOW > 0) {
+ out |= rt::O_NOFOLLOW;
+ };
+ if (flags & fs::flags::CLOEXEC > 0) {
+ out |= rt::O_CLOEXEC;
+ };
+ if (flags & fs::flags::PATH > 0) {
+ abort("fs::flags::PATH is not supported on FreeBSD");
+ };
+ if (flags & fs::flags::NOATIME > 0) {
+ abort("fs::flags::NOATIME is not supported on FreeBSD");
+ };
+ if (flags & fs::flags::TMPFILE > 0) {
+ abort("fs::flags::TMPFILE is not supported on FreeBSD");
+ };
+ return out;
+};
+
+fn fs_open_file(
+ fs: *fs::fs,
+ path: str,
+ flags: fs::flags...
+) (io::file | fs::error) = {
+ let oflags = fs::flags::RDONLY;
+ if (len(flags) == 0z) {
+ oflags |= fs::flags::NOCTTY | fs::flags::CLOEXEC;
+ };
+ for (let i = 0z; i < len(flags); i += 1z) {
+ oflags |= flags[i];
+ };
+ return _fs_open(fs, path, fsflags_to_bsd(oflags), 0);
+};
+
+fn fs_open(
+ fs: *fs::fs,
+ path: str,
+ flags: fs::flags...
+) (io::handle | fs::error) = fs_open_file(fs, path, flags...)?;
+
+fn fs_create_file(
+ fs: *fs::fs,
+ path: str,
+ mode: fs::mode,
+ flags: fs::flags...
+) (io::file | fs::error) = {
+ let oflags = fs::flags::RDONLY;
+ if (len(flags) == 0z) {
+ oflags |= fs::flags::NOCTTY | fs::flags::CLOEXEC;
+ };
+ for (let i = 0z; i < len(flags); i += 1z) {
+ oflags |= flags[i];
+ };
+ oflags |= fs::flags::CREATE;
+ return _fs_open(fs, path, fsflags_to_bsd(oflags), mode)?;
+};
+
+fn fs_create(
+ fs: *fs::fs,
+ path: str,
+ mode: fs::mode,
+ flags: fs::flags...
+) (io::handle | fs::error) = {
+ return fs_create_file(fs, path, mode, flags...)?;
+};
+
+fn fs_remove(fs: *fs::fs, path: str) (void | fs::error) = {
+ let fs = fs: *os_filesystem;
+ match (rt::unlinkat(fs.dirfd, path, 0)) {
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
+ };
+};
+
+fn fs_rename(fs: *fs::fs, oldpath: str, newpath: str) (void | fs::error) = {
+ let fs = fs: *os_filesystem;
+ match (rt::renameat(fs.dirfd, oldpath, fs.dirfd, newpath)) {
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
+ };
+};
+
+fn fs_stat(fs: *fs::fs, path: str) (fs::filestat | fs::error) = {
+ let fs = fs: *os_filesystem;
+ let st = rt::st { ... };
+ match (rt::fstatat(fs.dirfd, path, &st, rt::AT_SYMLINK_NOFOLLOW)) {
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
+ };
+ return fs::filestat {
+ mask = fs::stat_mask::UID
+ | fs::stat_mask::GID
+ | fs::stat_mask::SIZE
+ | fs::stat_mask::INODE
+ | fs::stat_mask::ATIME
+ | fs::stat_mask::MTIME
+ | fs::stat_mask::CTIME,
+ mode = st.mode: fs::mode,
+ uid = st.uid,
+ uid = st.gid,
+ sz = st.sz: size,
+ inode = st.ino,
+ atime = time::instant {
+ sec = st.atime.tv_sec,
+ nsec = st.atime.tv_nsec,
+ },
+ mtime = time::instant {
+ sec = st.mtime.tv_sec,
+ nsec = st.mtime.tv_nsec,
+ },
+ ctime = time::instant {
+ sec = st.ctime.tv_sec,
+ nsec = st.ctime.tv_nsec,
+ },
+ };
+};
+
+fn fs_readlink(fs: *fs::fs, path: str) (str | fs::error) = {
+ let fs = fs: *os_filesystem;
+ static let buf: [rt::PATH_MAX]u8 = [0...];
+ let z = match (rt::readlinkat(fs.dirfd, path, buf[..])) {
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case z: size =>
+ yield z;
+ };
+ return strings::dup(strings::fromutf8(buf[..z]));
+};
+
+fn fs_subdir(fs: *fs::fs, path: str) (*fs::fs | fs::error) = {
+ let fs = fs: *os_filesystem;
+ let flags = rt::O_RDONLY | rt::O_CLOEXEC | rt::O_DIRECTORY;
+
+ let fd: int = match (rt::openat(fs.dirfd, path, flags, 0)) {
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case fd: int =>
+ yield fd;
+ };
+
+ return dirfdopen(fd);
+};
+
+fn fs_rmdir(fs: *fs::fs, path: str) (void | fs::error) = {
+ let fs = fs: *os_filesystem;
+ match (rt::unlinkat(fs.dirfd, path, rt::AT_REMOVEDIR)) {
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
+ };
+};
+
+fn fs_mkdir(fs: *fs::fs, path: str) (void | fs::error) = {
+ let fs = fs: *os_filesystem;
+ match (rt::mkdirat(fs.dirfd, path, 0o755)) {
+ case err: rt::errno =>
+ switch (err) {
+ case rt::EISDIR =>
+ return errors::exists;
+ case =>
+ return errno_to_fs(err);
+ };
+ case void => void;
+ };
+};
+
+fn fs_chmod(fs: *fs::fs, path: str, mode: fs::mode) (void | fs::error) = {
+ let fs = fs: *os_filesystem;
+ match (rt::fchmodat(fs.dirfd, path, mode: uint, 0)) {
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
+ };
+};
+
+fn fs_chown(fs: *fs::fs, path: str, uid: uint, gid: uint) (void | fs::error) = {
+ let fs = fs: *os_filesystem;
+ match (rt::fchownat(fs.dirfd, path, uid, gid, 0)) {
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
+ };
+};
+
+fn resolve_part(parts: *[]str, part: str) void = {
+ if (part == ".") {
+ // no-op
+ void;
+ } else if (part == "..") {
+ if (len(parts) != 0) {
+ delete(parts[len(parts) - 1]);
+ };
+ } else {
+ append(parts, part);
+ };
+};
+
+fn fs_resolve(fs: *fs::fs, path: str) str = {
+ let parts: []str = [];
+ if (!path::abs(path)) {
+ let iter = path::iter(getcwd());
+ for (true) {
+ match (path::next(&iter)) {
+ case void =>
+ break;
+ case p: str =>
+ resolve_part(&parts, p);
+ };
+ };
+ };
+ let iter = path::iter(path);
+ for (true) {
+ match (path::next(&iter)) {
+ case void =>
+ break;
+ case p: str =>
+ resolve_part(&parts, p);
+ };
+ };
+ return path::join(parts...);
+};
+
+fn fs_close(fs: *fs::fs) void = {
+ let fs = fs: *os_filesystem;
+ rt::close(fs.dirfd)!;
+};
+
+def BUFSIZ: size = 2048;
+
+// Based on musl's readdir
+type os_iterator = struct {
+ iter: fs::iterator,
+ fd: int,
+ buf_pos: size,
+ buf_end: size,
+ buf: []u8,
+};
+
+fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = {
+ let fs = fs: *os_filesystem;
+ let flags = rt::O_RDONLY | rt::O_CLOEXEC | rt::O_DIRECTORY;
+ let fd: int = match (rt::openat(fs.dirfd, path, flags, 0)) {
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case fd: int =>
+ yield fd;
+ };
+
+ let buf = match (rt::malloc(fs.getdents_bufsz)) {
+ case v: *void =>
+ yield v: *[*]u8;
+ case null =>
+ return errors::nomem;
+ };
+ let iter = alloc(os_iterator {
+ iter = fs::iterator {
+ next = &iter_next,
+ },
+ fd = fd,
+ buf = buf[..fs.getdents_bufsz],
+ ...
+ });
+ return &iter.iter;
+};
+
+fn iter_next(iter: *fs::iterator) (fs::dirent | void) = {
+ let iter = iter: *os_iterator;
+ if (iter.buf_pos >= iter.buf_end) {
+ let n = rt::getdents(iter.fd,
+ iter.buf: *[*]u8, len(iter.buf)) as size;
+ if (n == 0) {
+ rt::close(iter.fd)!;
+ free(iter.buf);
+ free(iter);
+ return;
+ };
+ iter.buf_end = n;
+ iter.buf_pos = 0;
+ };
+ let de = &iter.buf[iter.buf_pos]: *rt::freebsd11_dirent;
+ iter.buf_pos += de.d_reclen;
+ let name = strings::fromc(&de.d_name: *const char);
+
+ let ftype: fs::mode = switch (de.d_type) {
+ case rt::DT_UNKNOWN =>
+ yield fs::mode::UNKNOWN;
+ case rt::DT_FIFO =>
+ yield fs::mode::FIFO;
+ case rt::DT_CHR =>
+ yield fs::mode::CHR;
+ case rt::DT_DIR =>
+ yield fs::mode::DIR;
+ case rt::DT_BLK =>
+ yield fs::mode::BLK;
+ case rt::DT_REG =>
+ yield fs::mode::REG;
+ case rt::DT_LNK =>
+ yield fs::mode::LINK;
+ case rt::DT_SOCK =>
+ yield fs::mode::SOCK;
+ case =>
+ yield fs::mode::UNKNOWN;
+ };
+ return fs::dirent {
+ name = name,
+ ftype = ftype,
+ };
+};
diff --git a/os/+freebsd/environ.ha b/os/+freebsd/environ.ha
@@ -0,0 +1,121 @@
+use bytes;
+use rt;
+use strings;
+use types;
+
+// The command line arguments provided to the program. By convention, the first
+// member is usually the name of the program.
+export let args: []str = [];
+
+// Statically allocate arg strings if there are few enough arguments, saves a
+// syscall if we don't need it.
+let args_static: [32]str = [""...];
+
+@init fn init_environ() void = {
+ if (rt::argc < len(args_static)) {
+ args = args_static[..rt::argc];
+ for (let i = 0z; i < rt::argc; i += 1) {
+ args[i] = strings::fromc(rt::argv[i]);
+ };
+ } else {
+ args = alloc([], rt::argc);
+ for (let i = 0z; i < rt::argc; i += 1) {
+ append(args, strings::fromc(rt::argv[i]));
+ };
+ };
+
+};
+
+@fini fn fini_environ() void = {
+ if (rt::argc >= len(args_static)) {
+ free(args);
+ };
+};
+
+// Looks up an environment variable and returns its value, or void if unset.
+export fn getenv(name: const str) (str | void) = {
+ const name_b = strings::toutf8(name);
+ for (let i = 0z; rt::envp[i] != null; i += 1) {
+ const item = rt::envp[i]: *[*]u8;
+ const ln = strings::cstrlen(item: *char);
+ const eq: size = match (bytes::index(item[..ln], '=': u8)) {
+ case void =>
+ abort("Environment violates System-V invariants");
+ case i: size =>
+ yield i;
+ };
+ if (bytes::equal(name_b, item[..eq])) {
+ const ln = strings::cstrlen(item: *const char);
+ return strings::fromutf8(item[eq+1..ln]);
+ };
+ };
+};
+
+// Looks up an environment variable and returns its value, or a default value if
+// unset.
+export fn tryenv(name: const str, default: str) str = match (getenv(name)) {
+case s: str =>
+ yield s;
+case void =>
+ yield default;
+};
+
+let envp: []str = [];
+
+// Returns a slice of the environment strings in the form KEY=VALUE.
+export fn getenvs() []str = {
+ if (len(envp) != 0) {
+ return envp;
+ };
+ for (let i = 0z; rt::envp[i] != null; i += 1) {
+ append(envp, strings::fromc(rt::envp[i]: *const char));
+ };
+ return envp;
+};
+
+// Returns the host kernel name
+export fn sysname() const str = {
+ static let buf: [512]u8 = [0...];
+ let sz: size = len(buf);
+ rt::sysctlbyname("kern.ostype", &buf, &sz, null, 0)!;
+ return strings::fromutf8(buf[..(sz - 1)]);
+};
+
+// Returns the host system hostname
+export fn hostname() const str = {
+ static let buf: [512]u8 = [0...];
+ let sz: size = len(buf);
+ rt::sysctlbyname("kern.hostname", &buf, &sz, null, 0)!;
+ return strings::fromutf8(buf[..(sz - 1)]);
+};
+
+// Returns the host kernel version
+export fn release() const str = {
+ static let buf: [512]u8 = [0...];
+ let sz: size = len(buf);
+ rt::sysctlbyname("kern.osrelease", &buf, &sz, null, 0)!;
+ return strings::fromutf8(buf[..(sz - 1)]);
+};
+
+// Returns the host operating system version
+export fn version() const str = {
+ static let buf: [512]u8 = [0...];
+ let sz: size = len(buf);
+ rt::sysctlbyname("kern.version", &buf, &sz, null, 0)!;
+ return strings::fromutf8(buf[..(sz - 1)]);
+};
+
+// Returns the host CPU architecture
+export fn machine() const str = {
+ static let buf: [512]u8 = [0...];
+ let sz: size = len(buf);
+ rt::sysctlbyname("hw.machine", &buf, &sz, null, 0)!;
+ const mach = strings::fromutf8(buf[..(sz - 1)]);
+ // Translate to Hare names
+ switch (mach) {
+ case "amd64" =>
+ return "x86_64";
+ case =>
+ return mach;
+ };
+};
diff --git a/os/+freebsd/exit.ha b/os/+freebsd/exit.ha
@@ -0,0 +1,4 @@
+use rt;
+
+// Exit the program with the provided status code.
+export @noreturn fn exit(status: int) void = rt::exit(status);
diff --git a/os/+freebsd/fs.ha b/os/+freebsd/fs.ha
@@ -0,0 +1,54 @@
+use errors;
+use fs;
+use path;
+use rt;
+use strings;
+
+@init fn init() void = {
+ static let cwd_fs = os_filesystem { ... };
+ cwd = static_dirfdopen(rt::AT_FDCWD, &cwd_fs);
+};
+
+// Returns the current working directory. The return value is statically
+// allocated and must be duplicated (see [[strings::dup]]) before calling getcwd
+// again.
+export fn getcwd() str = strings::fromc(rt::getcwd() as *const char);
+
+// Change the current working directory.
+export fn chdir(target: (*fs::fs | str)) (void | fs::error) = {
+ const path: str = match (target) {
+ case fs: *fs::fs =>
+ assert(fs.open == &fs_open);
+ let fs = fs: *os_filesystem;
+ match (rt::fchdir(fs.dirfd)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case void =>
+ return;
+ };
+ case s: str =>
+ yield s;
+ };
+ match (rt::chdir(path)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case void => void;
+ };
+};
+
+// Changes the root directory of the process. Generally requires the caller to
+// have root or otherwise elevated permissions.
+//
+// This function is not appropriate for sandboxing.
+export fn chroot(target: str) (void | fs::error) = {
+ match (rt::chroot(target)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case void => void;
+ };
+};
+
+// TODO: FreeBSD
+// export fn mkfifo(path: str, mode: fs::mode) (void | fs::error) = {
+// export fn mkblk(
+// export fn mkchr(
diff --git a/os/+freebsd/stdfd.ha b/os/+freebsd/stdfd.ha
@@ -0,0 +1,43 @@
+use bufio;
+use io;
+
+let static_stdin_bufio: bufio::bufstream = bufio::bufstream {
+ source = 0,
+ ...
+};
+
+let static_stdout_bufio: bufio::bufstream = bufio::bufstream {
+ source = 1,
+ ...
+};
+
+// The standard input. This handle is buffered.
+export let stdin: io::handle = 0;
+
+// The standard input, as an [[io::file]]. This handle is unbuffered.
+export let stdin_file: io::file = 0;
+
+// The standard output. This handle is buffered.
+export let stdout: io::handle = 1;
+
+// The standard output, as an [[io::file]]. This handle is unbuffered.
+export let stdout_file: io::file = 1;
+
+// The standard error.
+export let stderr: io::file = 2;
+
+// The recommended buffer size for reading from disk.
+export def BUFSIZ: size = 4096; // 4 KiB
+
+@init fn init_stdfd() void = {
+ static let stdinbuf: [BUFSIZ]u8 = [0...];
+ stdin = bufio::static_buffered(0, stdinbuf, [], &static_stdin_bufio);
+
+ static let stdoutbuf: [BUFSIZ]u8 = [0...];
+ stdout = bufio::static_buffered(1, [], stdoutbuf, &static_stdout_bufio);
+};
+
+@fini fn fini_stdfd() void = {
+ // Flush any pending writes
+ io::close(stdout);
+};
diff --git a/os/exec/exec+freebsd.ha b/os/exec/exec+freebsd.ha
@@ -0,0 +1,101 @@
+use errors;
+use rt;
+use strings;
+use os;
+
+export type platform_cmd = int;
+
+// Forks the current process, returning the pid of the child (to the parent) and
+// void (to the child), or an error.
+export fn fork() (int | void | error) = {
+ match (rt::fork()) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case i: (int | void) =>
+ return i;
+ };
+};
+
+fn open(path: str) (platform_cmd | error) = {
+ match (rt::access(path, rt::X_OK)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case b: bool =>
+ if (!b) {
+ return errors::noaccess;
+ };
+ };
+ // XXX: FreeBSD does not support O_PATH
+ match (rt::open(path, rt::O_RDONLY, 0u)) {
+ case fd: int =>
+ return fd;
+ case err: rt::errno =>
+ return errors::errno(err);
+ };
+};
+
+fn platform_finish(cmd: *command) void = rt::close(cmd.platform)!;
+
+fn platform_exec(cmd: *command) error = {
+ // We don't worry about freeing the return values from strings::to_c
+ // because once we exec(2) our heap is fried anyway
+ let argv: []nullable *const char = alloc([], len(cmd.argv) + 1z);
+ for (let i = 0z; i < len(cmd.argv); i += 1z) {
+ append(argv, strings::to_c(cmd.argv[i]));
+ };
+ append(argv, null);
+
+ let envp: nullable *[*]nullable *const char = null;
+ if (len(cmd.env) != 0) {
+ let env: []nullable *const char = alloc([], len(cmd.env) + 1);
+ for (let i = 0z; i < len(cmd.env); i += 1) {
+ append(env, strings::to_c(cmd.env[i]));
+ };
+ append(env, null);
+ envp = env: *[*]nullable *const char;
+ };
+
+ return errors::errno(rt::fexecve(cmd.platform,
+ argv: *[*]nullable *const char, envp));
+};
+
+fn platform_start(cmd: *command) (process | errors::error) = {
+ // TODO: Let the user configure clone more to their taste (e.g. SIGCHLD)
+ let pipe: [2]int = [0...];
+ match (rt::pipe2(&pipe, rt::O_CLOEXEC)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case void => void;
+ };
+
+ match (rt::fork()) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case pid: int =>
+ rt::close(pipe[1])!;
+ let errno: int = 0;
+ match (rt::read(pipe[0], &errno, size(int))) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case n: size =>
+ switch (n) {
+ case size(int) =>
+ return errors::errno(errno);
+ case 0 =>
+ return pid;
+ case =>
+ abort("Unexpected rt::read result");
+ };
+ };
+ case void =>
+ rt::close(pipe[0])!;
+ let err = platform_exec(cmd);
+ if (!(err is errors::opaque)) {
+ rt::exit(1);
+ };
+ let err = err as errors::opaque;
+ let err = &err.data: *rt::errno;
+ rt::write(pipe[1], &err, size(int))!;
+ rt::exit(1);
+ };
+};
diff --git a/os/exec/process+freebsd.ha b/os/exec/process+freebsd.ha
@@ -0,0 +1,134 @@
+use errors;
+use rt;
+use fmt;
+// TODO: Add function to wait on all/any children
+
+// Stores information about a child process.
+export type process = int;
+
+// Stores information about an exited process.
+export type status = struct {
+ status: int,
+ // Not all of these members are supported on all operating systems.
+ // Only utime and stime are guaranteed to be available.
+ rusage: struct {
+ // TODO: utime, stime
+ maxrss: i64,
+ ixrss: i64,
+ idrss: i64,
+ isrss: i64,
+ minflt: i64,
+ majflt: i64,
+ nswap: i64,
+ inblock: i64,
+ oublock: i64,
+ msgsnd: i64,
+ msgrcv: i64,
+ nsignals: i64,
+ nvcsw: i64,
+ nivcsw: i64,
+ },
+};
+
+fn rusage(st: *status, ru: *rt::rusage) void = {
+ st.rusage.maxrss = ru.ru_maxrss;
+ st.rusage.ixrss = ru.ru_ixrss;
+ st.rusage.idrss = ru.ru_idrss;
+ st.rusage.isrss = ru.ru_isrss;
+ st.rusage.minflt = ru.ru_minflt;
+ st.rusage.majflt = ru.ru_majflt;
+ st.rusage.nswap = ru.ru_nswap;
+ st.rusage.inblock = ru.ru_inblock;
+ st.rusage.oublock = ru.ru_oublock;
+ st.rusage.msgsnd = ru.ru_msgsnd;
+ st.rusage.msgrcv = ru.ru_msgrcv;
+ st.rusage.nsignals = ru.ru_nsignals;
+ st.rusage.nvcsw = ru.ru_nvcsw;
+ st.rusage.nivcsw = ru.ru_nivcsw;
+};
+
+// Waits for a process to complete, then returns its status information.
+export fn wait(proc: *process) (status | error) = {
+ let ru: rt::rusage = rt::rusage { ... };
+ let st: status = status { ... };
+ match (rt::wait4(*proc, &st.status, 0, &ru)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case pid: int =>
+ assert(pid == *proc);
+ };
+ rusage(&st, &ru);
+ return st;
+};
+
+// Checks for process completion, returning its status information on
+// completion, or void if it is still running.
+export fn peek(proc: *process) (status | void | error) = {
+ let ru: rt::rusage = rt::rusage { ... };
+ let st: status = status { ... };
+ match (rt::wait4(*proc, &st.status, 0, &ru)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case pid: int =>
+ switch (pid) {
+ case 0 =>
+ return;
+ case =>
+ assert(pid == *proc);
+ };
+ };
+ rusage(&st, &ru);
+ return st;
+};
+
+// The exit status code of a process.
+export type exited = int;
+
+// The signal number which caused a process to terminate.
+export type signaled = int;
+
+// The exit status of a process.
+export type exit_status = (exited | signaled);
+
+// Returns a human friendly string describing the exit status.
+export fn exitstr(status: exit_status) const str = {
+ static let buf: [1024]u8 = [0...];
+ match (status) {
+ case i: exited =>
+ switch (i) {
+ case 0 =>
+ return "exited normally";
+ case =>
+ return fmt::bsprintf(buf, "exited with status {}",
+ i: int);
+ };
+ case s: signaled =>
+ // TODO: Add signal name
+ return fmt::bsprintf(buf, "exited with signal {}", s: int);
+ };
+};
+
+// Returns the exit status of a completed process.
+export fn exit(stat: *status) exit_status = {
+ if (rt::wifexited(stat.status)) {
+ return rt::wexitstatus(stat.status): exited;
+ };
+ if (rt::wifsignaled(stat.status)) {
+ return rt::wtermsig(stat.status): signaled;
+ };
+ abort("Unexpected exit status");
+};
+
+// Checks the exit status of a completed process, returning void if successful,
+// or its status code as an error type if not.
+export fn check(stat: *status) (void | !exit_status) = {
+ if (rt::wifexited(stat.status)) {
+ switch (rt::wexitstatus(stat.status)) {
+ case 0 =>
+ return void;
+ case =>
+ return exit(stat);
+ };
+ };
+ return exit(stat);
+};
diff --git a/path/+freebsd.ha b/path/+freebsd.ha
@@ -0,0 +1,2 @@
+// Path separator, platform-specific.
+export def PATHSEP: u8 = '/': u32: u8;
diff --git a/rt/+freebsd/abort.ha b/rt/+freebsd/abort.ha
@@ -0,0 +1,9 @@
+fn platform_abort(msg: str) void = {
+ const prefix = "Abort: ";
+ const linefeed = "\n";
+ write(2, *(&prefix: **void): *const char, len(prefix)): void;
+ write(2, *(&msg: **void): *const char, len(msg)): void;
+ write(2, *(&linefeed: **void): *const char, 1): void;
+ kill(getpid(), SIGABRT): void;
+ for (true) void;
+};
diff --git a/rt/+freebsd/env.ha b/rt/+freebsd/env.ha
@@ -0,0 +1,3 @@
+export let argc: size = 0;
+export let argv: *[*]*char = null: *[*]*char;
+export let envp: *[*]nullable *char = null: *[*]nullable *char;
diff --git a/rt/+freebsd/errno.ha b/rt/+freebsd/errno.ha
@@ -0,0 +1,134 @@
+// Represents an error returned from the FreeBSD kernel.
+export type errno = !int;
+
+// Given an integer error number, wraps it in an error type.
+export fn wrap_errno(err: int) errno = err: errno;
+
+// Checks the return value from a FreeBSD syscall and, if found to be in error,
+// returns the appropriate error. Otherwise, returns the original value.
+fn wrap_return(r: u64) (errno | u64) = {
+ if (r > -4096: u64) {
+ return (-(r: i64)): int: errno;
+ };
+ return r;
+};
+
+// Obtains a human-friendly reading of an [[errno]] (e.g. "Operation not
+// permitted").
+export fn strerror(err: errno) str = {
+ // TODO
+ switch (err: int) {
+ case =>
+ return "[unknown errno]"; // TODO: snprintf to add errno?
+ };
+};
+
+// Gets the programmer-friendly name for an [[errno]] (e.g. EPERM).
+export fn errname(err: errno) str = {
+ // TODO
+ switch (err: int) {
+ case =>
+ return "[unknown errno]"; // TODO: snprintf to add errno?
+ };
+};
+
+export def EPERM: int = 1;
+export def ENOENT: int = 2;
+export def ESRCH: int = 3;
+export def EINTR: int = 4;
+export def EIO: int = 5;
+export def ENXIO: int = 6;
+export def E2BIG: int = 7;
+export def ENOEXEC: int = 8;
+export def EBADF: int = 9;
+export def ECHILD: int = 10;
+export def EDEADLK: int = 11;
+export def ENOMEM: int = 12;
+export def EACCES: int = 13;
+export def EFAULT: int = 14;
+export def ENOTBLK: int = 15;
+export def EBUSY: int = 16;
+export def EEXIST: int = 17;
+export def EXDEV: int = 18;
+export def ENODEV: int = 19;
+export def ENOTDIR: int = 20;
+export def EISDIR: int = 21;
+export def EINVAL: int = 22;
+export def ENFILE: int = 23;
+export def EMFILE: int = 24;
+export def ENOTTY: int = 25;
+export def ETXTBSY: int = 26;
+export def EFBIG: int = 27;
+export def ENOSPC: int = 28;
+export def ESPIPE: int = 29;
+export def EROFS: int = 30;
+export def EMLINK: int = 31;
+export def EPIPE: int = 32;
+export def EDOM: int = 33;
+export def ERANGE: int = 34;
+export def EAGAIN: int = 35;
+export def EWOULDBLOCK: int = EAGAIN;
+export def EINPROGRESS: int = 36;
+export def EALREADY: int = 37;
+export def ENOTSOCK: int = 38;
+export def EDESTADDRREQ: int = 39;
+export def EMSGSIZE: int = 40;
+export def EPROTOTYPE: int = 41;
+export def ENOPROTOOPT: int = 42;
+export def EPROTONOSUPPORT: int = 43;
+export def ESOCKTNOSUPPORT: int = 44;
+export def EOPNOTSUPP: int = 45;
+export def ENOTSUP: int = EOPNOTSUPP;
+export def EPFNOSUPPORT: int = 46;
+export def EAFNOSUPPORT: int = 47;
+export def EADDRINUSE: int = 48;
+export def EADDRNOTAVAIL: int = 49;
+export def ENETDOWN: int = 50;
+export def ENETUNREACH: int = 51;
+export def ENETRESET: int = 52;
+export def ECONNABORTED: int = 53;
+export def ECONNRESET: int = 54;
+export def ENOBUFS: int = 55;
+export def EISCONN: int = 56;
+export def ENOTCONN: int = 57;
+export def ESHUTDOWN: int = 58;
+export def ETOOMANYREFS: int = 59;
+export def ETIMEDOUT: int = 60;
+export def ETIME: int = ETIMEDOUT;
+export def ECONNREFUSED: int = 61;
+export def ELOOP: int = 62;
+export def ENAMETOOLONG: int = 63;
+export def EHOSTDOWN: int = 64;
+export def EHOSTUNREACH: int = 65;
+export def ENOTEMPTY: int = 66;
+export def EPROCLIM: int = 67;
+export def EUSERS: int = 68;
+export def EDQUOT: int = 69;
+export def ESTALE: int = 70;
+export def EREMOTE: int = 71;
+export def EBADRPC: int = 72;
+export def ERPCMISMATCH: int = 73;
+export def EPROGUNAVAIL: int = 74;
+export def EPROGMISMATCH: int = 75;
+export def EPROCUNAVAIL: int = 76;
+export def ENOLCK: int = 77;
+export def ENOSYS: int = 78;
+export def EFTYPE: int = 79;
+export def EAUTH: int = 80;
+export def ENEEDAUTH: int = 81;
+export def EIDRM: int = 82;
+export def ENOMSG: int = 83;
+export def EOVERFLOW: int = 84;
+export def ECANCELED: int = 85;
+export def EILSEQ: int = 86;
+export def ENOATTR: int = 87;
+export def EDOOFUS: int = 88;
+export def EBADMSG: int = 89;
+export def EMULTIHOP: int = 90;
+export def ENOLINK: int = 91;
+export def EPROTO: int = 92;
+export def ENOTCAPABLE: int = 93;
+export def ECAPMODE: int = 94;
+export def ENOTRECOVERABLE: int = 95;
+export def EOWNERDEAD: int = 96;
+export def EINTEGRITY: int = 97;
diff --git a/rt/+freebsd/platformstart.ha b/rt/+freebsd/platformstart.ha
@@ -0,0 +1,7 @@
+export @noreturn fn start_freebsd(iv: *[*]uintptr) void = {
+ // TODO: Find & parse auxv
+ argc = iv[0]: size;
+ argv = &iv[1]: *[*]*char;
+ envp = &argv[argc + 1]: *[*]nullable *char;
+ start_ha();
+};
diff --git a/rt/+freebsd/segmalloc.ha b/rt/+freebsd/segmalloc.ha
@@ -0,0 +1,20 @@
+// Allocates a segment.
+fn segmalloc(n: size) nullable *void = {
+ return match (mmap(null, n, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0)) {
+ case err: errno =>
+ assert(err == ENOMEM: errno);
+ yield null;
+ case p: *void =>
+ yield p;
+ };
+};
+
+// Frees a segment allocated with segmalloc.
+fn segfree(p: *void, s: size) void = {
+ match (munmap(p, s)) {
+ case err: errno =>
+ abort("munmap failed");
+ case void => void;
+ };
+};
diff --git a/rt/+freebsd/signal.ha b/rt/+freebsd/signal.ha
@@ -0,0 +1,45 @@
+// TODO: work when _NSIG != 32
+
+export fn sigemptyset(set: *sigset) int = {
+ for (let i = 0z; i < len(set.__bits); i += 1) {
+ set.__bits[i] = 0;
+ };
+ return 0;
+};
+
+export fn sigaddset(set: *sigset, signum: int) (int | errno) = {
+ if (signum > NSIG) {
+ return EINVAL;
+ };
+ signum -= 1;
+ set.__bits[signum >> 5] |= (1 << signum): u32;
+ return 0;
+};
+
+export fn sigdelset(set: *sigset, signum: int) (int | errno) = {
+ if (signum > NSIG) {
+ return EINVAL;
+ };
+ signum -= 1;
+ set.__bits[signum >> 5] &= ~(1 << signum: u32);
+ return 0;
+};
+
+export fn sigismember(set: *sigset, signum: int) (int | errno) = {
+ if (signum > NSIG) {
+ return EINVAL;
+ };
+ signum -= 1;
+ if ((set.__bits[signum >> 5] & (1 << signum: u32)) != 0) {
+ return 1;
+ } else {
+ return 0;
+ };
+};
+
+export fn sigfillset(set: *sigset) (int | errno) = {
+ for (let i = 0z; i < len(set.__bits); i += 1) {
+ set.__bits[i] = ~0u32;
+ };
+ return 0;
+};
diff --git a/rt/+freebsd/socket.ha b/rt/+freebsd/socket.ha
@@ -0,0 +1,306 @@
+export type sa_family_t = u8;
+
+export type in_addr = struct {
+ s_addr: u32
+};
+
+export type sockaddr_in = struct {
+ sin_len: u8,
+ sin_family: sa_family_t,
+ sin_port: u16,
+ sin_addr: in_addr,
+ __pad: [8]char,
+};
+
+export type in6_addr = struct {
+ union {
+ s6_addr: [16]u8,
+ s6_addr16: [8]u16,
+ s6_addr32: [4]u32,
+ }
+};
+
+export type sockaddr_in6 = struct {
+ sin6_len: u8,
+ sin6_family: sa_family_t,
+ sin6_port: u16,
+ sin6_flowinfo: u32,
+ sin6_addr: in6_addr,
+ sin6_scope_id: u32,
+};
+
+export def UNIX_PATH_MAX: size = 104;
+
+export type sockaddr_un = struct {
+ sun_len: u8,
+ sun_family: sa_family_t,
+ sun_path: [UNIX_PATH_MAX]char,
+};
+
+export type sockaddr = struct {
+ union {
+ in: sockaddr_in,
+ in6: sockaddr_in6,
+ un: sockaddr_un,
+ },
+};
+
+export def AF_UNSPEC: sa_family_t = 0;
+export def AF_UNIX: sa_family_t = 1;
+export def AF_LOCAL: sa_family_t = AF_UNIX;
+export def AF_INET: sa_family_t = 2;
+export def AF_IMPLINK: sa_family_t = 3;
+export def AF_PUP: sa_family_t = 4;
+export def AF_CHAOS: sa_family_t = 5;
+export def AF_NETBIOS: sa_family_t = 6;
+export def AF_ISO: sa_family_t = 7;
+export def AF_OSI: sa_family_t = AF_ISO;
+export def AF_ECMA: sa_family_t = 8;
+export def AF_DATAKIT: sa_family_t = 9;
+export def AF_CCITT: sa_family_t = 10;
+export def AF_SNA: sa_family_t = 11;
+export def AF_DECnet: sa_family_t = 12;
+export def AF_DLI: sa_family_t = 13;
+export def AF_LAT: sa_family_t = 14;
+export def AF_HYLINK: sa_family_t = 15;
+export def AF_APPLETALK: sa_family_t = 16;
+export def AF_ROUTE: sa_family_t = 17;
+export def AF_LINK: sa_family_t = 18;
+export def pseudo_AF_XTP: sa_family_t = 19;
+export def AF_COIP: sa_family_t = 20;
+export def AF_CNT: sa_family_t = 21;
+export def pseudo_AF_RTIP: sa_family_t = 22;
+export def AF_IPX: sa_family_t = 23;
+export def AF_SIP: sa_family_t = 24;
+export def pseudo_AF_PIP: sa_family_t = 25;
+export def AF_ISDN: sa_family_t = 26;
+export def AF_E164: sa_family_t = AF_ISDN;
+export def AF_INET6: sa_family_t = 28;
+export def AF_NATM: sa_family_t = 29;
+export def AF_ATM: sa_family_t = 30;
+export def AF_NETGRAPH: sa_family_t = 32;
+export def AF_SLOW: sa_family_t = 33;
+export def AF_SCLUSTER: sa_family_t = 34;
+export def AF_ARP: sa_family_t = 35;
+export def AF_BLUETOOTH: sa_family_t = 36;
+export def AF_IEEE80211: sa_family_t = 37;
+export def AF_INET_SDP: sa_family_t = 40;
+export def AF_INET6_SDP: sa_family_t = 42;
+export def AF_HYPERV: sa_family_t = 43;
+export def AF_MAX: sa_family_t = 43;
+export def AF_VENDOR00: sa_family_t = 39;
+export def AF_VENDOR01: sa_family_t = 41;
+export def AF_VENDOR03: sa_family_t = 45;
+export def AF_VENDOR04: sa_family_t = 47;
+export def AF_VENDOR05: sa_family_t = 49;
+export def AF_VENDOR06: sa_family_t = 51;
+export def AF_VENDOR07: sa_family_t = 53;
+export def AF_VENDOR08: sa_family_t = 55;
+export def AF_VENDOR09: sa_family_t = 57;
+export def AF_VENDOR10: sa_family_t = 59;
+export def AF_VENDOR11: sa_family_t = 61;
+export def AF_VENDOR12: sa_family_t = 63;
+export def AF_VENDOR13: sa_family_t = 65;
+export def AF_VENDOR14: sa_family_t = 67;
+export def AF_VENDOR15: sa_family_t = 69;
+export def AF_VENDOR16: sa_family_t = 71;
+export def AF_VENDOR17: sa_family_t = 73;
+export def AF_VENDOR18: sa_family_t = 75;
+export def AF_VENDOR19: sa_family_t = 77;
+export def AF_VENDOR20: sa_family_t = 79;
+export def AF_VENDOR21: sa_family_t = 81;
+export def AF_VENDOR22: sa_family_t = 83;
+export def AF_VENDOR23: sa_family_t = 85;
+export def AF_VENDOR24: sa_family_t = 87;
+export def AF_VENDOR25: sa_family_t = 89;
+export def AF_VENDOR26: sa_family_t = 91;
+export def AF_VENDOR27: sa_family_t = 93;
+export def AF_VENDOR28: sa_family_t = 95;
+export def AF_VENDOR29: sa_family_t = 97;
+export def AF_VENDOR30: sa_family_t = 99;
+export def AF_VENDOR31: sa_family_t = 101;
+export def AF_VENDOR32: sa_family_t = 103;
+export def AF_VENDOR33: sa_family_t = 105;
+export def AF_VENDOR34: sa_family_t = 107;
+export def AF_VENDOR35: sa_family_t = 109;
+export def AF_VENDOR36: sa_family_t = 111;
+export def AF_VENDOR37: sa_family_t = 113;
+export def AF_VENDOR38: sa_family_t = 115;
+export def AF_VENDOR39: sa_family_t = 117;
+export def AF_VENDOR40: sa_family_t = 119;
+export def AF_VENDOR41: sa_family_t = 121;
+export def AF_VENDOR42: sa_family_t = 123;
+export def AF_VENDOR43: sa_family_t = 125;
+export def AF_VENDOR44: sa_family_t = 127;
+export def AF_VENDOR45: sa_family_t = 129;
+export def AF_VENDOR46: sa_family_t = 131;
+export def AF_VENDOR47: sa_family_t = 133;
+
+export def SOCK_STREAM: int = 1;
+export def SOCK_DGRAM: int = 2;
+export def SOCK_RAW: int = 3;
+export def SOCK_RDM: int = 4;
+export def SOCK_SEQPACKET: int = 5;
+export def SOCK_CLOEXEC: int = 0x10000000;
+export def SOCK_NONBLOCK: int = 0x20000000;
+
+export def IPPROTO_HOPOPTS: int = 0;
+export def IPPROTO_IGMP: int = 2;
+export def IPPROTO_GGP: int = 3;
+export def IPPROTO_IPV4: int = 4;
+export def IPPROTO_IPIP: int = IPPROTO_IPV4;
+export def IPPROTO_ST: int = 7;
+export def IPPROTO_EGP: int = 8;
+export def IPPROTO_PIGP: int = 9;
+export def IPPROTO_RCCMON: int = 10;
+export def IPPROTO_NVPII: int = 11;
+export def IPPROTO_PUP: int = 12;
+export def IPPROTO_ARGUS: int = 13;
+export def IPPROTO_EMCON: int = 14;
+export def IPPROTO_XNET: int = 15;
+export def IPPROTO_CHAOS: int = 16;
+export def IPPROTO_MUX: int = 18;
+export def IPPROTO_MEAS: int = 19;
+export def IPPROTO_HMP: int = 20;
+export def IPPROTO_PRM: int = 21;
+export def IPPROTO_IDP: int = 22;
+export def IPPROTO_TRUNK1: int = 23;
+export def IPPROTO_TRUNK2: int = 24;
+export def IPPROTO_LEAF1: int = 25;
+export def IPPROTO_LEAF2: int = 26;
+export def IPPROTO_RDP: int = 27;
+export def IPPROTO_IRTP: int = 28;
+export def IPPROTO_TP: int = 29;
+export def IPPROTO_BLT: int = 30;
+export def IPPROTO_NSP: int = 31;
+export def IPPROTO_INP: int = 32;
+export def IPPROTO_DCCP: int = 33;
+export def IPPROTO_3PC: int = 34;
+export def IPPROTO_IDPR: int = 35;
+export def IPPROTO_XTP: int = 36;
+export def IPPROTO_DDP: int = 37;
+export def IPPROTO_CMTP: int = 38;
+export def IPPROTO_TPXX: int = 39;
+export def IPPROTO_IL: int = 40;
+export def IPPROTO_SDRP: int = 42;
+export def IPPROTO_ROUTING: int = 43;
+export def IPPROTO_FRAGMENT: int = 44;
+export def IPPROTO_IDRP: int = 45;
+export def IPPROTO_RSVP: int = 46;
+export def IPPROTO_GRE: int = 47;
+export def IPPROTO_MHRP: int = 48;
+export def IPPROTO_BHA: int = 49;
+export def IPPROTO_ESP: int = 50;
+export def IPPROTO_AH: int = 51;
+export def IPPROTO_INLSP: int = 52;
+export def IPPROTO_SWIPE: int = 53;
+export def IPPROTO_NHRP: int = 54;
+export def IPPROTO_MOBILE: int = 55;
+export def IPPROTO_TLSP: int = 56;
+export def IPPROTO_SKIP: int = 57;
+export def IPPROTO_ICMPV6: int = 58;
+export def IPPROTO_NONE: int = 59;
+export def IPPROTO_DSTOPTS: int = 60;
+export def IPPROTO_AHIP: int = 61;
+export def IPPROTO_CFTP: int = 62;
+export def IPPROTO_HELLO: int = 63;
+export def IPPROTO_SATEXPAK: int = 64;
+export def IPPROTO_KRYPTOLAN: int = 65;
+export def IPPROTO_RVD: int = 66;
+export def IPPROTO_IPPC: int = 67;
+export def IPPROTO_ADFS: int = 68;
+export def IPPROTO_SATMON: int = 69;
+export def IPPROTO_VISA: int = 70;
+export def IPPROTO_IPCV: int = 71;
+export def IPPROTO_CPNX: int = 72;
+export def IPPROTO_CPHB: int = 73;
+export def IPPROTO_WSN: int = 74;
+export def IPPROTO_PVP: int = 75;
+export def IPPROTO_BRSATMON: int = 76;
+export def IPPROTO_ND: int = 77;
+export def IPPROTO_WBMON: int = 78;
+export def IPPROTO_WBEXPAK: int = 79;
+export def IPPROTO_EON: int = 80;
+export def IPPROTO_VMTP: int = 81;
+export def IPPROTO_SVMTP: int = 82;
+export def IPPROTO_VINES: int = 83;
+export def IPPROTO_TTP: int = 84;
+export def IPPROTO_IGP: int = 85;
+export def IPPROTO_DGP: int = 86;
+export def IPPROTO_TCF: int = 87;
+export def IPPROTO_IGRP: int = 88;
+export def IPPROTO_OSPFIGP: int = 89;
+export def IPPROTO_SRPC: int = 90;
+export def IPPROTO_LARP: int = 91;
+export def IPPROTO_MTP: int = 92;
+export def IPPROTO_AX25: int = 93;
+export def IPPROTO_IPEIP: int = 94;
+export def IPPROTO_MICP: int = 95;
+export def IPPROTO_SCCSP: int = 96;
+export def IPPROTO_ETHERIP: int = 97;
+export def IPPROTO_ENCAP: int = 98;
+export def IPPROTO_APES: int = 99;
+// TODO: There are more but honestly I'm runing out of patience and I've never
+// seen anyone use these constants anyway
+
+export def MSG_OOB: int = 0x00000001;
+export def MSG_PEEK: int = 0x00000002;
+export def MSG_DONTROUTE: int = 0x00000004;
+export def MSG_EOR: int = 0x00000008;
+export def MSG_TRUNC: int = 0x00000010;
+export def MSG_CTRUNC: int = 0x00000020;
+export def MSG_WAITALL: int = 0x00000040;
+export def MSG_DONTWAIT: int = 0x00000080;
+export def MSG_EOF: int = 0x00000100;
+export def MSG_NOTIFICATION: int = 0x00002000;
+export def MSG_NBIO: int = 0x00004000;
+export def MSG_COMPAT: int = 0x00008000;
+export def MSG_NOSIGNAL: int = 0x00020000;
+export def MSG_CMSG_CLOEXEC: int = 0x00040000;
+export def MSG_WAITFORONE: int = 0x00080000;
+
+export def SO_DEBUG: int = 0x00000001;
+export def SO_ACCEPTCONN: int = 0x00000002;
+export def SO_REUSEADDR: int = 0x00000004;
+export def SO_KEEPALIVE: int = 0x00000008;
+export def SO_DONTROUTE: int = 0x00000010;
+export def SO_BROADCAST: int = 0x00000020;
+export def SO_USELOOPBACK: int = 0x00000040;
+export def SO_LINGER: int = 0x00000080;
+export def SO_OOBINLINE: int = 0x00000100;
+export def SO_REUSEPORT: int = 0x00000200;
+export def SO_TIMESTAMP: int = 0x00000400;
+export def SO_NOSIGPIPE: int = 0x00000800;
+export def SO_ACCEPTFILTER: int = 0x00001000;
+export def SO_BINTIME: int = 0x00002000;
+export def SO_NO_OFFLOAD: int = 0x00004000;
+export def SO_NO_DDP: int = 0x00008000;
+export def SO_REUSEPORT_LB: int = 0x00010000;
+export def SO_SNDBUF: int = 0x1001;
+export def SO_RCVBUF: int = 0x1002;
+export def SO_SNDLOWAT: int = 0x1003;
+export def SO_RCVLOWAT: int = 0x1004;
+export def SO_SNDTIMEO: int = 0x1005;
+export def SO_RCVTIMEO: int = 0x1006;
+export def SO_ERROR: int = 0x1007;
+export def SO_TYPE: int = 0x1008;
+export def SO_LABEL: int = 0x1009;
+export def SO_PEERLABEL: int = 0x1010;
+export def SO_LISTENQLIMIT: int = 0x1011;
+export def SO_LISTENQLEN: int = 0x1012;
+export def SO_LISTENINCQLEN: int = 0x1013;
+export def SO_SETFIB: int = 0x1014;
+export def SO_USER_COOKIE: int = 0x1015;
+export def SO_PROTOCOL: int = 0x1016;
+export def SO_PROTOTYPE: int = SO_PROTOCOL;
+export def SO_TS_CLOCK: int = 0x1017;
+export def SO_MAX_PACING_RATE: int = 0x1018;
+export def SO_DOMAIN: int = 0x1019;
+export def SO_TS_REALTIME_MICRO: int = 0;
+export def SO_TS_BINTIME: int = 1;
+export def SO_TS_REALTIME: int = 2;
+export def SO_TS_MONOTONIC: int = 3;
+export def SO_TS_DEFAULT: int = SO_TS_REALTIME_MICRO;
+export def SO_TS_CLOCK_MAX: int = SO_TS_MONOTONIC;
+
+export def SOL_SOCKET: int = 0xffff;
diff --git a/rt/+freebsd/start+aarch64.s b/rt/+freebsd/start+aarch64.s
@@ -0,0 +1,8 @@
+.text
+.global _start
+_start:
+ mov x29, #0
+ mov x30, #0
+ mov x0, sp
+ add sp, x0, #-16
+ b rt.start_freebsd
diff --git a/rt/+freebsd/start+riscv64.s b/rt/+freebsd/start+riscv64.s
@@ -0,0 +1,6 @@
+.text
+.global _start
+_start:
+ mv a0, sp
+ andi sp, sp, -16
+ tail rt.start_freebsd
diff --git a/rt/+freebsd/start+x86_64.s b/rt/+freebsd/start+x86_64.s
@@ -0,0 +1,5 @@
+.text
+.global _start
+_start:
+ xor %rbp, %rbp
+ call rt.start_freebsd
diff --git a/rt/+freebsd/syscall+aarch64.s b/rt/+freebsd/syscall+aarch64.s
@@ -0,0 +1,69 @@
+.section .text.rt.syscall0
+.global rt.syscall0
+rt.syscall0:
+ mov x8, x0
+ svc 0
+ ret
+
+.section .text.rt.syscall1
+.global rt.syscall1
+rt.syscall1:
+ mov x8, x0
+ mov x0, x1
+ svc 0
+ ret
+
+.section .text.rt.syscall2
+.global rt.syscall2
+rt.syscall2:
+ mov x8, x0
+ mov x0, x1
+ mov x1, x2
+ svc 0
+ ret
+
+.section .text.rt.syscall3
+.global rt.syscall3
+rt.syscall3:
+ mov x8, x0
+ mov x0, x1
+ mov x1, x2
+ mov x2, x3
+ svc 0
+ ret
+
+.section .text.rt.syscall4
+.global rt.syscall4
+rt.syscall4:
+ mov x8, x0
+ mov x0, x1
+ mov x1, x2
+ mov x2, x3
+ mov x3, x4
+ svc 0
+ ret
+
+.section .text.rt.syscall5
+.global rt.syscall5
+rt.syscall5:
+ mov x8, x0
+ mov x0, x1
+ mov x1, x2
+ mov x2, x3
+ mov x3, x4
+ mov x4, x5
+ svc 0
+ ret
+
+.section .text.rt.syscall6
+.global rt.syscall6
+rt.syscall6:
+ mov x8, x0
+ mov x0, x1
+ mov x1, x2
+ mov x2, x3
+ mov x3, x4
+ mov x4, x5
+ mov x5, x6
+ svc 0
+ ret
diff --git a/rt/+freebsd/syscall+riscv64.s b/rt/+freebsd/syscall+riscv64.s
@@ -0,0 +1,146 @@
+.section .text.rt.syscall0
+.global rt.syscall0
+rt.syscall0:
+ addi sp, sp, -32
+ sd s0, 24(sp)
+ addi s0, sp, 32
+ sd a0, -24(s0)
+ ld a7, -24(s0)
+ ecall
+ mv a5, a0
+ mv a0, a5
+ ld s0, 24(sp)
+ addi sp, sp, 32
+ jr ra
+
+.section .text.rt.syscall1
+.global rt.syscall1
+rt.syscall1:
+ addi sp, sp, -32
+ sd s0, 24(sp)
+ addi s0, sp, 32
+ sd a0, -24(s0)
+ sd a1, -32(s0)
+ ld a7, -24(s0)
+ ld a0, -32(s0)
+ ecall
+ mv a5, a0
+ mv a0, a5
+ ld s0, 24(sp)
+ addi sp, sp, 32
+ jr ra
+
+.section .text.rt.syscall2
+.global rt.syscall2
+rt.syscall2:
+ addi sp, sp, -48
+ sd s0, 40(sp)
+ addi s0, sp, 48
+ sd a0, -24(s0)
+ sd a1, -32(s0)
+ sd a2, -40(s0)
+ ld a7, -24(s0)
+ ld a0, -32(s0)
+ ld a1, -40(s0)
+ ecall
+ mv a5, a0
+ mv a0, a5
+ ld s0, 40(sp)
+ addi sp, sp, 48
+ jr ra
+
+.section .text.rt.syscall3
+.global rt.syscall3
+rt.syscall3:
+ addi sp, sp, -48
+ sd s0, 40(sp)
+ addi s0, sp, 48
+ sd a0, -24(s0)
+ sd a1, -32(s0)
+ sd a2, -40(s0)
+ sd a3, -48(s0)
+ ld a7, -24(s0)
+ ld a0, -32(s0)
+ ld a1, -40(s0)
+ ld a2, -48(s0)
+ ecall
+ mv a5, a0
+ mv a0, a5
+ ld s0, 40(sp)
+ addi sp, sp, 48
+ jr ra
+
+.section .text.rt.syscall4
+.global rt.syscall4
+rt.syscall4:
+ addi sp, sp, -64
+ sd s0, 56(sp)
+ addi s0, sp, 64
+ sd a0, -24(s0)
+ sd a1, -32(s0)
+ sd a2, -40(s0)
+ sd a3, -48(s0)
+ sd a4, -56(s0)
+ ld a7, -24(s0)
+ ld a0, -32(s0)
+ ld a1, -40(s0)
+ ld a2, -48(s0)
+ ld a3, -56(s0)
+ ecall
+ mv a5, a0
+ mv a0, a5
+ ld s0, 56(sp)
+ addi sp, sp, 64
+ jr ra
+
+.section .text.rt.syscall5
+.global rt.syscall5
+rt.syscall5:
+ addi sp, sp, -64
+ sd s0, 56(sp)
+ addi s0, sp, 64
+ sd a0, -24(s0)
+ sd a1, -32(s0)
+ sd a2, -40(s0)
+ sd a3, -48(s0)
+ sd a4, -56(s0)
+ sd a5, -64(s0)
+ ld a7, -24(s0)
+ ld a0, -32(s0)
+ ld a1, -40(s0)
+ ld a2, -48(s0)
+ ld a3, -56(s0)
+ ld a4, -64(s0)
+ ecall
+ mv a5, a0
+ mv a0, a5
+ ld s0, 56(sp)
+ addi sp, sp, 64
+ jr ra
+
+.section .text.rt.syscall6
+.global rt.syscall6
+rt.syscall6:
+ addi sp, sp, -80
+ sd s0, 72(sp)
+ addi s0, sp, 80
+ sd a0, -24(s0)
+ sd a1, -32(s0)
+ sd a2, -40(s0)
+ sd a3, -48(s0)
+ sd a4, -56(s0)
+ sd a5, -64(s0)
+ sd a6, -72(s0)
+ ld a7, -24(s0)
+ ld a0, -32(s0)
+ ld a1, -40(s0)
+ ld a2, -48(s0)
+ ld a3, -56(s0)
+ ld a4, -64(s0)
+ ld a5, -72(s0)
+ ecall
+ mv a5, a0
+ mv a0, a5
+ ld s0, 72(sp)
+ addi sp, sp, 80
+ jr ra
diff --git a/rt/+freebsd/syscall+x86_64.s b/rt/+freebsd/syscall+x86_64.s
@@ -0,0 +1,81 @@
+.section .text
+error:
+ neg %rax
+ ret
+
+.section .text.rt.syscall0
+.global rt.syscall0
+rt.syscall0:
+ movq %rdi, %rax
+ syscall
+ jc error
+ ret
+
+.section .text.rt.syscall1
+.global rt.syscall1
+rt.syscall1:
+ movq %rdi, %rax
+ movq %rsi, %rdi
+ syscall
+ jc error
+ ret
+
+.section .text.rt.syscall2
+.global rt.syscall2
+rt.syscall2:
+ movq %rdi, %rax
+ movq %rsi, %rdi
+ movq %rdx, %rsi
+ syscall
+ jc error
+ ret
+
+.section .text.rt.syscall3
+.global rt.syscall3
+rt.syscall3:
+ movq %rdi, %rax
+ movq %rsi, %rdi
+ movq %rdx, %rsi
+ movq %rcx, %rdx
+ syscall
+ jc error
+ ret
+
+.section .text.rt.syscall4
+.global rt.syscall4
+rt.syscall4:
+ movq %rdi, %rax
+ movq %r8, %r10
+ movq %rsi, %rdi
+ movq %rdx, %rsi
+ movq %rcx, %rdx
+ syscall
+ jc error
+ ret
+
+.section .text.rt.syscall5
+.global rt.syscall5
+rt.syscall5:
+ movq %rdi, %rax
+ movq %r8, %r10
+ movq %rsi, %rdi
+ movq %r9, %r8
+ movq %rdx, %rsi
+ movq %rcx, %rdx
+ syscall
+ jc error
+ ret
+
+.section .text.rt.syscall6
+.global rt.syscall6
+rt.syscall6:
+ movq %rdi, %rax
+ movq %r8, %r10
+ movq %rsi, %rdi
+ movq %r9, %r8
+ movq %rdx, %rsi
+ movq 8(%rsp), %r9
+ movq %rcx, %rdx
+ syscall
+ jc error
+ ret
diff --git a/rt/+freebsd/syscallno.ha b/rt/+freebsd/syscallno.ha
@@ -0,0 +1,419 @@
+export def SYS_syscall: u64 = 0;
+export def SYS_exit: u64 = 1;
+export def SYS_fork: u64 = 2;
+export def SYS_read: u64 = 3;
+export def SYS_write: u64 = 4;
+export def SYS_open: u64 = 5;
+export def SYS_close: u64 = 6;
+export def SYS_wait4: u64 = 7;
+export def SYS_link: u64 = 9;
+export def SYS_unlink: u64 = 10;
+export def SYS_chdir: u64 = 12;
+export def SYS_fchdir: u64 = 13;
+export def SYS_freebsd11_mknod: u64 = 14;
+export def SYS_chmod: u64 = 15;
+export def SYS_chown: u64 = 16;
+export def SYS_break: u64 = 17;
+export def SYS_getpid: u64 = 20;
+export def SYS_mount: u64 = 21;
+export def SYS_unmount: u64 = 22;
+export def SYS_setuid: u64 = 23;
+export def SYS_getuid: u64 = 24;
+export def SYS_geteuid: u64 = 25;
+export def SYS_ptrace: u64 = 26;
+export def SYS_recvmsg: u64 = 27;
+export def SYS_sendmsg: u64 = 28;
+export def SYS_recvfrom: u64 = 29;
+export def SYS_accept: u64 = 30;
+export def SYS_getpeername: u64 = 31;
+export def SYS_getsockname: u64 = 32;
+export def SYS_access: u64 = 33;
+export def SYS_chflags: u64 = 34;
+export def SYS_fchflags: u64 = 35;
+export def SYS_sync: u64 = 36;
+export def SYS_kill: u64 = 37;
+export def SYS_getppid: u64 = 39;
+export def SYS_dup: u64 = 41;
+export def SYS_freebsd10_pipe: u64 = 42;
+export def SYS_getegid: u64 = 43;
+export def SYS_profil: u64 = 44;
+export def SYS_ktrace: u64 = 45;
+export def SYS_getgid: u64 = 47;
+export def SYS_getlogin: u64 = 49;
+export def SYS_setlogin: u64 = 50;
+export def SYS_acct: u64 = 51;
+export def SYS_sigaltstack: u64 = 53;
+export def SYS_ioctl: u64 = 54;
+export def SYS_reboot: u64 = 55;
+export def SYS_revoke: u64 = 56;
+export def SYS_symlink: u64 = 57;
+export def SYS_readlink: u64 = 58;
+export def SYS_execve: u64 = 59;
+export def SYS_umask: u64 = 60;
+export def SYS_chroot: u64 = 61;
+export def SYS_msync: u64 = 65;
+export def SYS_vfork: u64 = 66;
+export def SYS_sbrk: u64 = 69;
+export def SYS_sstk: u64 = 70;
+export def SYS_freebsd11_vadvise: u64 = 72;
+export def SYS_munmap: u64 = 73;
+export def SYS_mprotect: u64 = 74;
+export def SYS_madvise: u64 = 75;
+export def SYS_mincore: u64 = 78;
+export def SYS_getgroups: u64 = 79;
+export def SYS_setgroups: u64 = 80;
+export def SYS_getpgrp: u64 = 81;
+export def SYS_setpgid: u64 = 82;
+export def SYS_setitimer: u64 = 83;
+export def SYS_swapon: u64 = 85;
+export def SYS_getitimer: u64 = 86;
+export def SYS_getdtablesize: u64 = 89;
+export def SYS_dup2: u64 = 90;
+export def SYS_fcntl: u64 = 92;
+export def SYS_select: u64 = 93;
+export def SYS_fsync: u64 = 95;
+export def SYS_setpriority: u64 = 96;
+export def SYS_socket: u64 = 97;
+export def SYS_connect: u64 = 98;
+export def SYS_getpriority: u64 = 100;
+export def SYS_bind: u64 = 104;
+export def SYS_setsockopt: u64 = 105;
+export def SYS_listen: u64 = 106;
+export def SYS_gettimeofday: u64 = 116;
+export def SYS_getrusage: u64 = 117;
+export def SYS_getsockopt: u64 = 118;
+export def SYS_readv: u64 = 120;
+export def SYS_writev: u64 = 121;
+export def SYS_settimeofday: u64 = 122;
+export def SYS_fchown: u64 = 123;
+export def SYS_fchmod: u64 = 124;
+export def SYS_setreuid: u64 = 126;
+export def SYS_setregid: u64 = 127;
+export def SYS_rename: u64 = 128;
+export def SYS_flock: u64 = 131;
+export def SYS_mkfifo: u64 = 132;
+export def SYS_sendto: u64 = 133;
+export def SYS_shutdown: u64 = 134;
+export def SYS_socketpair: u64 = 135;
+export def SYS_mkdir: u64 = 136;
+export def SYS_rmdir: u64 = 137;
+export def SYS_utimes: u64 = 138;
+export def SYS_adjtime: u64 = 140;
+export def SYS_setsid: u64 = 147;
+export def SYS_quotactl: u64 = 148;
+export def SYS_nlm_syscall: u64 = 154;
+export def SYS_nfssvc: u64 = 155;
+export def SYS_lgetfh: u64 = 160;
+export def SYS_getfh: u64 = 161;
+export def SYS_sysarch: u64 = 165;
+export def SYS_rtprio: u64 = 166;
+export def SYS_semsys: u64 = 169;
+export def SYS_msgsys: u64 = 170;
+export def SYS_shmsys: u64 = 171;
+export def SYS_setfib: u64 = 175;
+export def SYS_ntp_adjtime: u64 = 176;
+export def SYS_setgid: u64 = 181;
+export def SYS_setegid: u64 = 182;
+export def SYS_seteuid: u64 = 183;
+export def SYS_freebsd11_stat: u64 = 188;
+export def SYS_freebsd11_fstat: u64 = 189;
+export def SYS_freebsd11_lstat: u64 = 190;
+export def SYS_pathconf: u64 = 191;
+export def SYS_fpathconf: u64 = 192;
+export def SYS_getrlimit: u64 = 194;
+export def SYS_setrlimit: u64 = 195;
+export def SYS_freebsd11_getdirentries: u64 = 196;
+export def SYS___syscall: u64 = 198;
+export def SYS___sysctl: u64 = 202;
+export def SYS_mlock: u64 = 203;
+export def SYS_munlock: u64 = 204;
+export def SYS_undelete: u64 = 205;
+export def SYS_futimes: u64 = 206;
+export def SYS_getpgid: u64 = 207;
+export def SYS_poll: u64 = 209;
+export def SYS_freebsd7___semctl: u64 = 220;
+export def SYS_semget: u64 = 221;
+export def SYS_semop: u64 = 222;
+export def SYS_freebsd7_msgctl: u64 = 224;
+export def SYS_msgget: u64 = 225;
+export def SYS_msgsnd: u64 = 226;
+export def SYS_msgrcv: u64 = 227;
+export def SYS_shmat: u64 = 228;
+export def SYS_freebsd7_shmctl: u64 = 229;
+export def SYS_shmdt: u64 = 230;
+export def SYS_shmget: u64 = 231;
+export def SYS_clock_gettime: u64 = 232;
+export def SYS_clock_settime: u64 = 233;
+export def SYS_clock_getres: u64 = 234;
+export def SYS_ktimer_create: u64 = 235;
+export def SYS_ktimer_delete: u64 = 236;
+export def SYS_ktimer_settime: u64 = 237;
+export def SYS_ktimer_gettime: u64 = 238;
+export def SYS_ktimer_getoverrun: u64 = 239;
+export def SYS_nanosleep: u64 = 240;
+export def SYS_ffclock_getcounter: u64 = 241;
+export def SYS_ffclock_setestimate: u64 = 242;
+export def SYS_ffclock_getestimate: u64 = 243;
+export def SYS_clock_nanosleep: u64 = 244;
+export def SYS_clock_getcpuclockid2: u64 = 247;
+export def SYS_ntp_gettime: u64 = 248;
+export def SYS_minherit: u64 = 250;
+export def SYS_rfork: u64 = 251;
+export def SYS_issetugid: u64 = 253;
+export def SYS_lchown: u64 = 254;
+export def SYS_aio_read: u64 = 255;
+export def SYS_aio_write: u64 = 256;
+export def SYS_lio_listio: u64 = 257;
+export def SYS_freebsd11_getdents: u64 = 272;
+export def SYS_lchmod: u64 = 274;
+export def SYS_lutimes: u64 = 276;
+export def SYS_freebsd11_nstat: u64 = 278;
+export def SYS_freebsd11_nfstat: u64 = 279;
+export def SYS_freebsd11_nlstat: u64 = 280;
+export def SYS_preadv: u64 = 289;
+export def SYS_pwritev: u64 = 290;
+export def SYS_fhopen: u64 = 298;
+export def SYS_freebsd11_fhstat: u64 = 299;
+export def SYS_modnext: u64 = 300;
+export def SYS_modstat: u64 = 301;
+export def SYS_modfnext: u64 = 302;
+export def SYS_modfind: u64 = 303;
+export def SYS_kldload: u64 = 304;
+export def SYS_kldunload: u64 = 305;
+export def SYS_kldfind: u64 = 306;
+export def SYS_kldnext: u64 = 307;
+export def SYS_kldstat: u64 = 308;
+export def SYS_kldfirstmod: u64 = 309;
+export def SYS_getsid: u64 = 310;
+export def SYS_setresuid: u64 = 311;
+export def SYS_setresgid: u64 = 312;
+export def SYS_aio_return: u64 = 314;
+export def SYS_aio_suspend: u64 = 315;
+export def SYS_aio_cancel: u64 = 316;
+export def SYS_aio_error: u64 = 317;
+export def SYS_yield: u64 = 321;
+export def SYS_mlockall: u64 = 324;
+export def SYS_munlockall: u64 = 325;
+export def SYS___getcwd: u64 = 326;
+export def SYS_sched_setparam: u64 = 327;
+export def SYS_sched_getparam: u64 = 328;
+export def SYS_sched_setscheduler: u64 = 329;
+export def SYS_sched_getscheduler: u64 = 330;
+export def SYS_sched_yield: u64 = 331;
+export def SYS_sched_get_priority_max: u64 = 332;
+export def SYS_sched_get_priority_min: u64 = 333;
+export def SYS_sched_rr_get_u64erval: u64 = 334;
+export def SYS_utrace: u64 = 335;
+export def SYS_kldsym: u64 = 337;
+export def SYS_jail: u64 = 338;
+export def SYS_nnpfs_syscall: u64 = 339;
+export def SYS_sigprocmask: u64 = 340;
+export def SYS_sigsuspend: u64 = 341;
+export def SYS_sigpending: u64 = 343;
+export def SYS_sigtimedwait: u64 = 345;
+export def SYS_sigwaitinfo: u64 = 346;
+export def SYS___acl_get_file: u64 = 347;
+export def SYS___acl_set_file: u64 = 348;
+export def SYS___acl_get_fd: u64 = 349;
+export def SYS___acl_set_fd: u64 = 350;
+export def SYS___acl_delete_file: u64 = 351;
+export def SYS___acl_delete_fd: u64 = 352;
+export def SYS___acl_aclcheck_file: u64 = 353;
+export def SYS___acl_aclcheck_fd: u64 = 354;
+export def SYS_extattrctl: u64 = 355;
+export def SYS_extattr_set_file: u64 = 356;
+export def SYS_extattr_get_file: u64 = 357;
+export def SYS_extattr_delete_file: u64 = 358;
+export def SYS_aio_waitcomplete: u64 = 359;
+export def SYS_getresuid: u64 = 360;
+export def SYS_getresgid: u64 = 361;
+export def SYS_kqueue: u64 = 362;
+export def SYS_freebsd11_kevent: u64 = 363;
+export def SYS_extattr_set_fd: u64 = 371;
+export def SYS_extattr_get_fd: u64 = 372;
+export def SYS_extattr_delete_fd: u64 = 373;
+export def SYS___setugid: u64 = 374;
+export def SYS_eaccess: u64 = 376;
+export def SYS_afs3_syscall: u64 = 377;
+export def SYS_nmount: u64 = 378;
+export def SYS___mac_get_proc: u64 = 384;
+export def SYS___mac_set_proc: u64 = 385;
+export def SYS___mac_get_fd: u64 = 386;
+export def SYS___mac_get_file: u64 = 387;
+export def SYS___mac_set_fd: u64 = 388;
+export def SYS___mac_set_file: u64 = 389;
+export def SYS_kenv: u64 = 390;
+export def SYS_lchflags: u64 = 391;
+export def SYS_uuidgen: u64 = 392;
+export def SYS_sendfile: u64 = 393;
+export def SYS_mac_syscall: u64 = 394;
+export def SYS_freebsd11_getfsstat: u64 = 395;
+export def SYS_freebsd11_statfs: u64 = 396;
+export def SYS_freebsd11_fstatfs: u64 = 397;
+export def SYS_freebsd11_fhstatfs: u64 = 398;
+export def SYS_ksem_close: u64 = 400;
+export def SYS_ksem_post: u64 = 401;
+export def SYS_ksem_wait: u64 = 402;
+export def SYS_ksem_trywait: u64 = 403;
+export def SYS_ksem_init: u64 = 404;
+export def SYS_ksem_open: u64 = 405;
+export def SYS_ksem_unlink: u64 = 406;
+export def SYS_ksem_getvalue: u64 = 407;
+export def SYS_ksem_destroy: u64 = 408;
+export def SYS___mac_get_pid: u64 = 409;
+export def SYS___mac_get_link: u64 = 410;
+export def SYS___mac_set_link: u64 = 411;
+export def SYS_extattr_set_link: u64 = 412;
+export def SYS_extattr_get_link: u64 = 413;
+export def SYS_extattr_delete_link: u64 = 414;
+export def SYS___mac_execve: u64 = 415;
+export def SYS_sigaction: u64 = 416;
+export def SYS_sigreturn: u64 = 417;
+export def SYS_getcontext: u64 = 421;
+export def SYS_setcontext: u64 = 422;
+export def SYS_swapcontext: u64 = 423;
+export def SYS_swapoff: u64 = 424;
+export def SYS___acl_get_link: u64 = 425;
+export def SYS___acl_set_link: u64 = 426;
+export def SYS___acl_delete_link: u64 = 427;
+export def SYS___acl_aclcheck_link: u64 = 428;
+export def SYS_sigwait: u64 = 429;
+export def SYS_thr_create: u64 = 430;
+export def SYS_thr_exit: u64 = 431;
+export def SYS_thr_self: u64 = 432;
+export def SYS_thr_kill: u64 = 433;
+export def SYS_jail_attach: u64 = 436;
+export def SYS_extattr_list_fd: u64 = 437;
+export def SYS_extattr_list_file: u64 = 438;
+export def SYS_extattr_list_link: u64 = 439;
+export def SYS_ksem_timedwait: u64 = 441;
+export def SYS_thr_suspend: u64 = 442;
+export def SYS_thr_wake: u64 = 443;
+export def SYS_kldunloadf: u64 = 444;
+export def SYS_audit: u64 = 445;
+export def SYS_auditon: u64 = 446;
+export def SYS_getauid: u64 = 447;
+export def SYS_setauid: u64 = 448;
+export def SYS_getaudit: u64 = 449;
+export def SYS_setaudit: u64 = 450;
+export def SYS_getaudit_addr: u64 = 451;
+export def SYS_setaudit_addr: u64 = 452;
+export def SYS_auditctl: u64 = 453;
+export def SYS__umtx_op: u64 = 454;
+export def SYS_thr_new: u64 = 455;
+export def SYS_sigqueue: u64 = 456;
+export def SYS_kmq_open: u64 = 457;
+export def SYS_kmq_setattr: u64 = 458;
+export def SYS_kmq_timedreceive: u64 = 459;
+export def SYS_kmq_timedsend: u64 = 460;
+export def SYS_kmq_notify: u64 = 461;
+export def SYS_kmq_unlink: u64 = 462;
+export def SYS_abort2: u64 = 463;
+export def SYS_thr_set_name: u64 = 464;
+export def SYS_aio_fsync: u64 = 465;
+export def SYS_rtprio_thread: u64 = 466;
+export def SYS_sctp_peeloff: u64 = 471;
+export def SYS_sctp_generic_sendmsg: u64 = 472;
+export def SYS_sctp_generic_sendmsg_iov: u64 = 473;
+export def SYS_sctp_generic_recvmsg: u64 = 474;
+export def SYS_pread: u64 = 475;
+export def SYS_pwrite: u64 = 476;
+export def SYS_mmap: u64 = 477;
+export def SYS_lseek: u64 = 478;
+export def SYS_truncate: u64 = 479;
+export def SYS_ftruncate: u64 = 480;
+export def SYS_thr_kill2: u64 = 481;
+export def SYS_freebsd12_shm_open: u64 = 482;
+export def SYS_shm_unlink: u64 = 483;
+export def SYS_cpuset: u64 = 484;
+export def SYS_cpuset_setid: u64 = 485;
+export def SYS_cpuset_getid: u64 = 486;
+export def SYS_cpuset_getaffinity: u64 = 487;
+export def SYS_cpuset_setaffinity: u64 = 488;
+export def SYS_faccessat: u64 = 489;
+export def SYS_fchmodat: u64 = 490;
+export def SYS_fchownat: u64 = 491;
+export def SYS_fexecve: u64 = 492;
+export def SYS_freebsd11_fstatat: u64 = 493;
+export def SYS_futimesat: u64 = 494;
+export def SYS_linkat: u64 = 495;
+export def SYS_mkdirat: u64 = 496;
+export def SYS_mkfifoat: u64 = 497;
+export def SYS_freebsd11_mknodat: u64 = 498;
+export def SYS_openat: u64 = 499;
+export def SYS_readlinkat: u64 = 500;
+export def SYS_renameat: u64 = 501;
+export def SYS_symlinkat: u64 = 502;
+export def SYS_unlinkat: u64 = 503;
+export def SYS_posix_openpt: u64 = 504;
+export def SYS_gssd_syscall: u64 = 505;
+export def SYS_jail_get: u64 = 506;
+export def SYS_jail_set: u64 = 507;
+export def SYS_jail_remove: u64 = 508;
+export def SYS_freebsd12_closefrom: u64 = 509;
+export def SYS___semctl: u64 = 510;
+export def SYS_msgctl: u64 = 511;
+export def SYS_shmctl: u64 = 512;
+export def SYS_lpathconf: u64 = 513;
+export def SYS___cap_rights_get: u64 = 515;
+export def SYS_cap_enter: u64 = 516;
+export def SYS_cap_getmode: u64 = 517;
+export def SYS_pdfork: u64 = 518;
+export def SYS_pdkill: u64 = 519;
+export def SYS_pdgetpid: u64 = 520;
+export def SYS_pselect: u64 = 522;
+export def SYS_getloginclass: u64 = 523;
+export def SYS_setloginclass: u64 = 524;
+export def SYS_rctl_get_racct: u64 = 525;
+export def SYS_rctl_get_rules: u64 = 526;
+export def SYS_rctl_get_limits: u64 = 527;
+export def SYS_rctl_add_rule: u64 = 528;
+export def SYS_rctl_remove_rule: u64 = 529;
+export def SYS_posix_fallocate: u64 = 530;
+export def SYS_posix_fadvise: u64 = 531;
+export def SYS_wait6: u64 = 532;
+export def SYS_cap_rights_limit: u64 = 533;
+export def SYS_cap_ioctls_limit: u64 = 534;
+export def SYS_cap_ioctls_get: u64 = 535;
+export def SYS_cap_fcntls_limit: u64 = 536;
+export def SYS_cap_fcntls_get: u64 = 537;
+export def SYS_bindat: u64 = 538;
+export def SYS_connectat: u64 = 539;
+export def SYS_chflagsat: u64 = 540;
+export def SYS_accept4: u64 = 541;
+export def SYS_pipe2: u64 = 542;
+export def SYS_aio_mlock: u64 = 543;
+export def SYS_procctl: u64 = 544;
+export def SYS_ppoll: u64 = 545;
+export def SYS_futimens: u64 = 546;
+export def SYS_utimensat: u64 = 547;
+export def SYS_fdatasync: u64 = 550;
+export def SYS_fstat: u64 = 551;
+export def SYS_fstatat: u64 = 552;
+export def SYS_fhstat: u64 = 553;
+export def SYS_getdirentries: u64 = 554;
+export def SYS_statfs: u64 = 555;
+export def SYS_fstatfs: u64 = 556;
+export def SYS_getfsstat: u64 = 557;
+export def SYS_fhstatfs: u64 = 558;
+export def SYS_mknodat: u64 = 559;
+export def SYS_kevent: u64 = 560;
+export def SYS_cpuset_getdomain: u64 = 561;
+export def SYS_cpuset_setdomain: u64 = 562;
+export def SYS_getrandom: u64 = 563;
+export def SYS_getfhat: u64 = 564;
+export def SYS_fhlink: u64 = 565;
+export def SYS_fhlinkat: u64 = 566;
+export def SYS_fhreadlink: u64 = 567;
+export def SYS_funlinkat: u64 = 568;
+export def SYS_copy_file_range: u64 = 569;
+export def SYS___sysctlbyname: u64 = 570;
+export def SYS_shm_open2: u64 = 571;
+export def SYS_shm_rename: u64 = 572;
+export def SYS_sigfastblock: u64 = 573;
+export def SYS___realpathat: u64 = 574;
+export def SYS_close_range: u64 = 575;
+export def SYS_rpctls_syscall: u64 = 576;
+export def SYS___specialfd: u64 = 577;
+export def SYS_aio_writev: u64 = 578;
+export def SYS_aio_readv: u64 = 579;
diff --git a/rt/+freebsd/syscalls.ha b/rt/+freebsd/syscalls.ha
@@ -0,0 +1,472 @@
+fn syscall0(_: u64) u64;
+fn syscall1(_: u64, _: u64) u64;
+fn syscall2(_: u64, _: u64, _: u64) u64;
+fn syscall3(_: u64, _: u64, _: u64, _: u64) u64;
+fn syscall4(_: u64, _: u64, _: u64, _: u64, _: u64) u64;
+fn syscall5(_: u64, _: u64, _: u64, _: u64, _: u64, _: u64) u64;
+fn syscall6(_: u64, _: u64, _: u64, _: u64, _: u64, _: u64, _: u64) u64;
+
+export def PATH_MAX: size = 1024z;
+export type path = (str | []u8 | *const char);
+let pathbuf: [PATH_MAX + 1]u8 = [0...];
+
+fn copy_kpath(path: path, buf: []u8) (*const char | errno) = {
+ let path = match (path) {
+ case c: *const char =>
+ return c;
+ case s: str =>
+ let ptr = &s: *struct {
+ buf: *[*]u8,
+ length: size,
+ capacity: size,
+ };
+ yield ptr.buf[..ptr.length];
+ case b: []u8 =>
+ yield b;
+ };
+ if (len(path) + 1 >= len(pathbuf)) {
+ return ENAMETOOLONG;
+ };
+ memcpy(buf: *[*]u8, path: *[*]u8, len(path));
+ buf[len(path)] = 0;
+ return buf: *[*]u8: *const char;
+};
+
+// NUL terminates a string and stores it in a static buffer of PATH_MAX+1 bytes
+// in length.
+fn kpath(path: path) (*const char | errno) = {
+ return copy_kpath(path, pathbuf);
+};
+
+export fn read(fd: int, buf: *void, count: size) (size | errno) = {
+ return wrap_return(syscall3(SYS_read,
+ fd: u64, buf: uintptr: u64, count: u64))?: size;
+};
+
+export fn write(fd: int, buf: *const void, count: size) (size | errno) = {
+ return wrap_return(syscall3(SYS_write,
+ fd: u64, buf: uintptr: u64, count: u64))?: size;
+};
+
+export fn close(fd: int) (void | errno) = {
+ wrap_return(syscall1(SYS_close, fd: u64))?;
+ return;
+};
+
+export fn lseek(fd: int, off: i64, whence: uint) (i64 | errno) = {
+ return wrap_return(syscall3(SYS_lseek,
+ fd: u64, off: u64, whence: u64))?: i64;
+};
+
+export fn pipe2(pipefd: *[2]int, flags: int) (void | errno) = {
+ wrap_return(syscall2(SYS_pipe2, pipefd: uintptr: u64, flags: u64))?;
+ return;
+};
+
+export fn ioctl(fd: int, req: u64, arg: nullable *void) (int | errno) = {
+ return wrap_return(syscall3(SYS_ioctl, fd: u64,
+ req, arg: uintptr: u64))?: int;
+};
+
+export fn openat(
+ dirfd: int,
+ path: path,
+ flags: int,
+ mode: uint,
+) (int | errno) = {
+ let path = kpath(path)?;
+ return wrap_return(syscall4(SYS_openat, dirfd: u64,
+ path: uintptr: u64, flags: u64, mode: u64))?: int;
+};
+
+export fn open(path: str, flags: int, mode: uint) (int | errno) = {
+ return openat(AT_FDCWD, path, flags, mode);
+};
+
+export fn unlink(path: path) (void | errno) = {
+ let path = kpath(path)?;
+ wrap_return(syscall3(SYS_unlinkat,
+ AT_FDCWD: u64, path: uintptr: u64, 0u64))?;
+ return;
+};
+
+export fn renameat(
+ olddirfd: int,
+ oldpath: str,
+ newdirfd: int,
+ newpath: str,
+) (void | errno) = {
+ let oldpath = kpath(oldpath)?;
+ static let newpathbuf: [PATH_MAX + 1]u8 = [0...];
+ let newpath = copy_kpath(newpath, newpathbuf)?;
+ wrap_return(syscall4(SYS_renameat,
+ olddirfd: u64, oldpath: uintptr: u64,
+ newdirfd: u64, newpath: uintptr: u64))?;
+ return;
+};
+
+export fn unlinkat(dirfd: int, path: path, flags: int) (void | errno) = {
+ let path = kpath(path)?;
+ wrap_return(syscall3(SYS_unlinkat,
+ dirfd: u64, path: uintptr: u64, flags: u64))?;
+ return;
+};
+
+export fn fstatat(fd: int, path: path, stat: *st, flag: int) (void | errno) = {
+ let path = kpath(path)?;
+ let fbstat = freebsd11_stat { ... };
+ wrap_return(syscall4(SYS_freebsd11_fstatat, fd: u64,
+ path: uintptr: u64, &fbstat: uintptr: u64, flag: u64))?;
+ stat.dev = fbstat.st_dev;
+ stat.ino = fbstat.st_ino;
+ stat.mode = fbstat.st_mode;
+ stat.nlink = fbstat.st_nlink;
+ stat.uid = fbstat.st_uid;
+ stat.gid = fbstat.st_gid;
+ stat.rdev = fbstat.st_rdev;
+ stat.atime.tv_sec = fbstat.st_atim.tv_sec;
+ stat.atime.tv_nsec = fbstat.st_atim.tv_nsec: i64;
+ stat.mtime.tv_sec = fbstat.st_mtim.tv_sec;
+ stat.mtime.tv_nsec = fbstat.st_mtim.tv_nsec: i64;
+ stat.ctime.tv_sec = fbstat.st_ctim.tv_sec;
+ stat.ctime.tv_nsec = fbstat.st_ctim.tv_nsec: i64;
+ stat.btime.tv_sec = fbstat.st_birthtim.tv_sec;
+ stat.btime.tv_nsec = fbstat.st_birthtim.tv_nsec: i64;
+ stat.sz = fbstat.st_size;
+ stat.blocks = fbstat.st_blocks;
+ stat.blksz = fbstat.st_blksize;
+ stat.flags = fbstat.st_flags;
+ return;
+};
+
+export fn readlinkat(
+ dirfd: int,
+ path: path,
+ buf: []u8,
+) (size | errno) = {
+ let path = kpath(path)?;
+ return wrap_return(syscall4(SYS_readlinkat,
+ dirfd: u64, path: uintptr: u64,
+ buf: *[*]u8: uintptr: u64,
+ len(buf): u64))?: size;
+};
+
+export fn mkdirat(dirfd: int, path: path, mode: uint) (void | errno) = {
+ let path = kpath(path)?;
+ wrap_return(syscall3(SYS_mkdirat,
+ dirfd: u64, path: uintptr: u64, mode: u64))?;
+ return;
+};
+
+export fn fchmodat(dirfd: int, path: path, mode: uint, flags: int) (void | errno) = {
+ let path = kpath(path)?;
+ wrap_return(syscall4(SYS_fchmodat,
+ dirfd: u64, path: uintptr: u64, mode: u64, flags: u64))?;
+ return;
+};
+
+export fn fchownat(dirfd: int, path: path, uid: uint, gid: uint, flags: int) (void | errno) = {
+ let path = kpath(path)?;
+ wrap_return(syscall5(SYS_fchownat,
+ dirfd: u64, path: uintptr: u64, uid: u32, gid: u32, flags: u64))?;
+ return;
+};
+
+export fn faccessat(
+ dirfd: int,
+ path: path,
+ mode: int,
+ flags: int,
+) (bool | errno) = {
+ let path = kpath(path)?;
+ match (wrap_return(syscall4(SYS_faccessat, dirfd: u64,
+ path: uintptr: u64, mode: u64, flags: u64))) {
+ case err: errno =>
+ switch (err) {
+ case EACCES =>
+ return false;
+ case =>
+ return err;
+ };
+ case n: u64 =>
+ assert(n == 0);
+ return true;
+ };
+};
+
+// The use of this function is discouraged, as it can create race conditions.
+// TOCTOU is preferred: attempt to simply use the resource you need and handle
+// any access errors which occur.
+export fn access(path: path, mode: int) (bool | errno) =
+ faccessat(AT_FDCWD, path, mode, 0);
+
+// TODO: Consider updating this to use SYS_freebsd11_getdirentries
+export fn getdents(dirfd: int, buf: *void, nbytes: size) (size | errno) = {
+ return wrap_return(syscall3(SYS_freebsd11_getdents, dirfd: u64,
+ buf: uintptr: u64, nbytes: u64))?: size;
+};
+
+// The return value is statically allocated and must be duplicated before
+// calling getcwd again.
+export fn getcwd() (*const char | errno) = {
+ static let pathbuf: [PATH_MAX + 1]u8 = [0...];
+ wrap_return(syscall2(SYS___getcwd,
+ &pathbuf: *[*]u8: uintptr: u64,
+ PATH_MAX + 1))?;
+ return &pathbuf: *const char;
+};
+
+export fn fchdir(fd: int) (void | errno) = {
+ wrap_return(syscall1(SYS_fchdir, fd: u64))?;
+ return;
+};
+
+export fn chdir(path: path) (void | errno) = {
+ let path = kpath(path)?;
+ wrap_return(syscall1(SYS_chdir, path: uintptr: u64))?;
+ return;
+};
+
+export fn chroot(path: path) (void | errno) = {
+ let path = kpath(path)?;
+ wrap_return(syscall1(SYS_chroot, path: uintptr: u64))?;
+ return;
+};
+
+export fn mmap(
+ addr: nullable *void,
+ length: size,
+ prot: uint,
+ flags: uint,
+ fd: int,
+ offs: size
+) (errno | *void) = {
+ return wrap_return(syscall6(SYS_mmap, addr: uintptr: u64,
+ length: u64, prot: u64, flags: u64,
+ fd: u64, offs: u64))?: uintptr: *void;
+};
+
+export fn munmap(addr: *void, length: size) (void | errno) = {
+ wrap_return(syscall2(SYS_munmap, addr: uintptr: u64, length: u64))?;
+ return;
+};
+
+export @noreturn fn exit(status: int) void = syscall1(SYS_exit, status: u64);
+
+export fn kill(pid: int, signal: int) (void | errno) = {
+ wrap_return(syscall2(SYS_kill, pid: u64, signal: u64))?;
+ return;
+};
+
+export fn fork() (int | void | errno) = {
+ let n = wrap_return(syscall0(SYS_fork))?: int;
+ switch (n) {
+ case 0 =>
+ return;
+ case =>
+ return n;
+ };
+};
+
+export fn fexecve(fd: int, argv: *[*]nullable *const char,
+ envp: *[*]nullable *const char) errno = {
+ return match (wrap_return(syscall3(SYS_fexecve, fd: u64,
+ argv: uintptr: u64, envp: uintptr: u64))) {
+ case err: errno =>
+ yield err;
+ case u64 =>
+ abort("unreachable");
+ };
+};
+
+export fn wait4(
+ pid: int,
+ wstatus: *int,
+ options: int,
+ rusage: *rusage,
+) (int | errno) = {
+ return wrap_return(syscall4(SYS_wait4,
+ pid: u64, wstatus: uintptr: u64,
+ options: u64, rusage: uintptr: u64))?: int;
+};
+
+export fn wifexited(status: int) bool = wtermsig(status) == 0;
+export fn wexitstatus(status: int) int = (status & 0xff00) >> 8;
+
+export fn wtermsig(status: int) int = status & 0x7f;
+export fn wifsignaled(status: int) bool =
+ wtermsig(status) != 0o177 && wtermsig(status) != 0 && status != 0x13;
+
+export fn getpid() int = syscall0(SYS_getpid): int;
+
+export fn getpriority(which: int, who: id_t) (int | errno) = {
+ return wrap_return(syscall2(SYS_setpriority,
+ which: u64, who: u64))?: int;
+};
+
+export fn setpriority(which: int, who: id_t, prio: int) (void | errno) = {
+ wrap_return(syscall3(SYS_setpriority, which: u64, who: u64, prio: u64))?;
+ return;
+};
+
+export fn umask(mode: mode_t) (mode_t | errno) = {
+ return wrap_return(syscall1(SYS_umask, mode: u64))?: mode_t;
+};
+
+export fn setresuid(uid: uid_t, euid: uid_t, suid: uid_t) (void | errno) = {
+ wrap_return(syscall3(SYS_setresuid, uid: u64, euid: u64, suid: u64))?;
+ return;
+};
+
+export fn setresgid(gid: gid_t, egid: gid_t, sgid: gid_t) (void | errno) = {
+ wrap_return(syscall3(SYS_setresgid, gid: u64, egid: u64, sgid: u64))?;
+ return;
+};
+
+export fn getresuid(uid: *uid_t, euid: *uid_t, suid: *uid_t) (void | errno) = {
+ wrap_return(syscall3(SYS_getresuid,
+ uid: uintptr: u64,
+ euid: uintptr: u64,
+ suid: uintptr: u64))?;
+ return;
+};
+
+export fn getresgid(gid: *gid_t, egid: *gid_t, sgid: *gid_t) (void | errno) = {
+ wrap_return(syscall3(SYS_getresgid,
+ gid: uintptr: u64,
+ egid: uintptr: u64,
+ sgid: uintptr: u64))?;
+ return;
+};
+
+export fn clock_gettime(clock_id: int, tp: *timespec) (void | errno) = {
+ wrap_return(syscall2(SYS_clock_gettime,
+ clock_id: u64, tp: uintptr: u64))?;
+ return;
+};
+
+export fn nanosleep(req: *const timespec, rem: *timespec) (void | errno) = {
+ wrap_return(syscall2(SYS_nanosleep,
+ req: uintptr: u64, rem: uintptr: u64))?;
+ return;
+};
+
+export fn getrandom(buf: *void, bufln: size, flags: uint) (size | errno) = {
+ return wrap_return(syscall3(SYS_getrandom,
+ buf: uintptr: u64, bufln: u64, flags: u64))?: size;
+};
+
+export type fcntl_arg = (void | int | *st_flock | *u64);
+
+export fn fcntl(fd: int, cmd: int, arg: fcntl_arg) (int | errno) = {
+ let _fd = fd: u64, _cmd = cmd: u64;
+ return wrap_return(match (arg) {
+ case void =>
+ yield syscall2(SYS_fcntl, _fd, _cmd);
+ case i: int =>
+ yield syscall3(SYS_fcntl, _fd, _cmd, i: u64);
+ case l: *st_flock =>
+ yield syscall3(SYS_fcntl, _fd, _cmd, l: uintptr: u64);
+ case u: *u64 =>
+ yield syscall3(SYS_fcntl, _fd, _cmd, u: uintptr: u64);
+ })?: int;
+};
+
+export fn ppoll(
+ fds: *[*]pollfd,
+ nfds: nfds_t,
+ timeout: const nullable *timespec,
+ sigmask: const nullable *sigset,
+) (int | errno) = {
+ return wrap_return(syscall4(SYS_ppoll, fds: uintptr: u64, nfds: u64,
+ timeout: uintptr: u64, sigmask: uintptr: u64))?: int;
+};
+
+export fn poll(fds: *[*]pollfd, nfds: nfds_t, timeout: int) (int | errno) = {
+ const ts = timespec {
+ tv_sec = timeout % 1000,
+ tv_nsec = timeout * 1000000,
+ };
+ return ppoll(fds, nfds, (if (timeout != -1) &ts else null), null);
+};
+
+export fn socket(domain: int, type_: int, protocol: int) (int | errno) = {
+ return wrap_return(syscall3(SYS_socket,
+ domain: u64, type_: u64, protocol: u64))?: int;
+};
+
+export fn connect(sockfd: int, addr: *const sockaddr, addrlen: u32) (int | errno) = {
+ return wrap_return(syscall3(SYS_connect,
+ sockfd: u64, addr: uintptr: u64, addrlen: u64))?: int;
+};
+
+export fn bind(sockfd: int, addr: *const sockaddr, addrlen: u32) (int | errno) = {
+ return wrap_return(syscall3(SYS_bind,
+ sockfd: u64, addr: uintptr: u64, addrlen: u64))?: int;
+};
+
+export fn listen(sockfd: int, backlog: u32) (int | errno) = {
+ return wrap_return(syscall2(SYS_listen,
+ sockfd: u64, backlog: u64))?: int;
+};
+
+export fn accept(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = {
+ return wrap_return(syscall3(SYS_accept,
+ sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int;
+};
+
+export fn recvfrom(sockfd: int, buf: *void, len_: size, flags: int,
+ src_addr: nullable *sockaddr, addrlen: nullable *u32
+) (size | errno) = {
+ return wrap_return(syscall6(SYS_recvfrom,
+ sockfd: u64, buf: uintptr: u64, len_: u64, flags: u64,
+ src_addr: uintptr: u64, addrlen: uintptr: u64))?: size;
+};
+
+export fn sendto(sockfd: int, buf: *void, len_: size, flags: int,
+ dest_addr: nullable *sockaddr, addrlen: u32
+) (size | errno) = {
+ return wrap_return(syscall6(SYS_sendto,
+ sockfd: u64, buf: uintptr: u64, len_: u64, flags: u64,
+ dest_addr: uintptr: u64, addrlen: u64))?: size;
+};
+
+export fn recv(sockfd: int, buf: *void, len_: size, flags: int) (size | errno) = {
+ return recvfrom(sockfd, buf, len_, flags, null, null);
+};
+
+export fn send(sockfd: int, buf: *void, len_: size, flags: int) (size | errno) = {
+ return sendto(sockfd, buf, len_, flags, null, 0);
+};
+
+export fn getsockopt(sockfd: int, level: int, optname: int, optval: nullable *void, optlen: nullable *u32) (int | errno) = {
+ return wrap_return(syscall5(SYS_getsockopt,
+ sockfd: u64, level: u64, optname: u64,
+ optval: uintptr: u64, optlen: uintptr: u64))?: int;
+};
+
+export fn setsockopt(sockfd: int, level: int, optname: int, optval: *void, optlen: u32) (int | errno) = {
+ return wrap_return(syscall5(SYS_setsockopt,
+ sockfd: u64, level: u64, optname: u64,
+ optval: uintptr: u64, optlen: u64))?: int;
+};
+
+export fn getsockname(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = {
+ return wrap_return(syscall3(SYS_getsockname,
+ sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int;
+};
+
+export fn getpeername(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = {
+ return wrap_return(syscall3(SYS_getpeername,
+ sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int;
+};
+
+export fn sysctlbyname(name: str, oldp: nullable *void, oldlenp: nullable *size,
+ newp: nullable *const void, newlen: size) (void | errno) = {
+ let kname = kpath(name)?;
+ wrap_return(syscall6(SYS___sysctlbyname,
+ kname: uintptr: u64, len(name): u64,
+ oldp: uintptr: u64, oldlenp: uintptr: u64,
+ newp: uintptr: u64, newlen: u64))?;
+ return;
+};
diff --git a/rt/+freebsd/types.ha b/rt/+freebsd/types.ha
@@ -0,0 +1,290 @@
+export type time_t = i64;
+export type suseconds_t = i64;
+export type dev_t = u64;
+export type ino_t = u64;
+export type nlink_t = u64;
+export type id_t = uint;
+export type pid_t = uint;
+export type uid_t = uint;
+export type gid_t = uint;
+export type off_t = i64;
+export type blkcnt_t = i64;
+export type blksize_t = i32;
+export type fflags_t = u32;
+export type mode_t = u16;
+export type nfds_t = uint;
+
+export def NSIG: int = 32;
+
+export type sigset = struct {
+ __bits: [4]u32,
+};
+
+export type sigact = struct {
+ union {
+ sa_handler: *fn (_: int) void,
+ sa_sigaction: *fn (_: int, _: *siginfo, _: *void) void,
+ },
+ sa_flags: int,
+ sa_mask: sigset,
+};
+
+export type siginfo = struct {
+ // TODO: Fill in more of this
+ si_signo: int,
+ si_errno: int,
+ si_code: int,
+ si_pid: pid_t,
+ si_uid: u32,
+ si_status: int,
+ si_addr: *void,
+};
+
+export type pollfd = struct {
+ fd: int,
+ events: i16,
+ revents: i16,
+};
+
+export type timespec = struct {
+ tv_sec: time_t,
+ tv_nsec: i64,
+};
+
+export type timeval = struct {
+ tv_sec: time_t,
+ tv_usec: suseconds_t,
+};
+
+export type st_flock = struct {
+ l_start: off_t,
+ l_len: off_t,
+ l_pid: pid_t,
+ l_type: i16,
+ l_whence: i16,
+ l_sysid: int,
+};
+
+export type st = struct {
+ dev: dev_t,
+ ino: ino_t,
+ nlink: nlink_t,
+ mode: mode_t,
+ uid: uid_t,
+ gid: gid_t,
+ rdev: dev_t,
+ atime: timespec,
+ mtime: timespec,
+ ctime: timespec,
+ btime: timespec,
+ sz: off_t,
+ blocks: blkcnt_t,
+ blksz: blksize_t,
+ flags: fflags_t,
+};
+
+export type freebsd11_stat = struct {
+ st_dev: u32,
+ st_ino: u32,
+ st_mode: mode_t,
+ st_nlink: u16,
+ st_uid: uid_t,
+ st_gid: gid_t,
+ st_rdev: u32,
+ st_atim: timespec,
+ st_mtim: timespec,
+ st_ctim: timespec,
+ st_size: off_t,
+ st_blocks: blkcnt_t,
+ st_blksize: blksize_t,
+ st_flags: fflags_t,
+ st_gen: u32,
+ st_lspare: u32,
+ st_birthtim: timespec,
+};
+
+export type freebsd11_dirent = struct {
+ d_fileno: u32,
+ d_reclen: u16,
+ d_type: u8,
+ d_namlen: u8,
+ d_name: [*]char,
+};
+
+export type winsize = struct {
+ ws_row: u16,
+ ws_col: u16,
+ ws_xpixel: u16,
+ ws_ypixel: u16,
+};
+
+export type rusage = struct {
+ ru_utime: timeval,
+ ru_stime: timeval,
+ ru_maxrss: i64,
+ ru_ixrss: i64,
+ ru_idrss: i64,
+ ru_isrss: i64,
+ ru_minflt: i64,
+ ru_majflt: i64,
+ ru_nswap: i64,
+ ru_inblock: i64,
+ ru_oublock: i64,
+ ru_msgsnd: i64,
+ ru_msgrcv: i64,
+ ru_nsignals: i64,
+ ru_nvcsw: i64,
+ ru_nivcsw: i64,
+};
+
+export def TIOCGWINSZ: u64 = 0x40087468;
+
+export def DT_UNKNOWN: u8 = 0;
+export def DT_FIFO: u8 = 1;
+export def DT_CHR: u8 = 2;
+export def DT_DIR: u8 = 4;
+export def DT_BLK: u8 = 6;
+export def DT_REG: u8 = 8;
+export def DT_LNK: u8 = 10;
+export def DT_SOCK: u8 = 12;
+export def DT_WHT: u8 = 14;
+
+export def O_RDONLY: int = 0x0000;
+export def O_WRONLY: int = 0x0001;
+export def O_RDWR: int = 0x0002;
+export def O_NONBLOCK: int = 0x0004;
+export def O_APPEND: int = 0x0008;
+export def O_SHLOCK: int = 0x0010;
+export def O_EXLOCK: int = 0x0020;
+export def O_ASYNC: int = 0x0040;
+export def O_FSYNC: int = 0x0080;
+export def O_SYNC: int = 0x0080;
+export def O_NOFOLLOW: int = 0x0100;
+export def O_CREAT: int = 0x0200;
+export def O_TRUNC: int = 0x0400;
+export def O_EXCL: int = 0x0800;
+export def O_NOCTTY: int = 0x8000;
+export def O_DIRECT: int = 0x00010000;
+export def O_DIRECTORY: int = 0x00020000;
+export def O_EXEC: int = 0x00040000;
+export def O_TTY_INIT: int = 0x00080000;
+export def O_CLOEXEC: int = 0x00100000;
+export def O_DSYNC: int = 0x01000000;
+
+export def AT_FDCWD: int = -100;
+export def AT_EACCESS: int = 0x0100;
+export def AT_SYMLINK_NOFOLLOW: int = 0x0200;
+export def AT_SYMLINK_FOLLOW: int = 0x0400;
+export def AT_REMOVEDIR: int = 0x0800;
+export def AT_RESOLVE_BENEATH: int = 0x2000;
+
+export def MAP_SHARED: uint = 0x0001;
+export def MAP_PRIVATE: uint = 0x0002;
+export def MAP_FIXED: uint = 0x0010;
+export def MAP_HASSEMAPHORE: uint = 0x0200;
+export def MAP_STACK: uint = 0x0400;
+export def MAP_NOSYNC: uint = 0x0800;
+export def MAP_FILE: uint = 0x0000;
+export def MAP_ANON: uint = 0x1000;
+export def MAP_GUARD: uint = 0x00002000;
+export def MAP_EXCL: uint = 0x00004000;
+export def MAP_NOCORE: uint = 0x00020000;
+export def MAP_PREFAULT_READ: uint = 0x00040000;
+export def MAP_32BIT: uint = 0x00080000;
+
+export def PROT_NONE: uint = 0x00;
+export def PROT_READ: uint = 0x01;
+export def PROT_WRITE: uint = 0x02;
+export def PROT_EXEC: uint = 0x04;
+
+export def SIGHUP: int = 1;
+export def SIGINT: int = 2;
+export def SIGQUIT: int = 3;
+export def SIGILL: int = 4;
+export def SIGTRAP: int = 5;
+export def SIGABRT: int = 6;
+export def SIGFPE: int = 8;
+export def SIGKILL: int = 9;
+export def SIGBUS: int = 10;
+export def SIGSEGV: int = 11;
+export def SIGSYS: int = 12;
+export def SIGPIPE: int = 13;
+export def SIGALRM: int = 14;
+export def SIGTERM: int = 15;
+export def SIGSTOP: int = 17;
+export def SIGTSTP: int = 18;
+export def SIGCONT: int = 19;
+export def SIGCHLD: int = 20;
+export def SIGTTIN: int = 21;
+export def SIGTTOU: int = 22;
+export def SIGIO: int = 23;
+export def SIGXCPU: int = 24;
+export def SIGXFSZ: int = 25;
+export def SIGVTALRM: int = 26;
+export def SIGPROF: int = 27;
+export def SIGWINCH: int = 28;
+export def SIGINFO: int = 29;
+export def SIGUSR1: int = 30;
+export def SIGUSR2: int = 31;
+export def SIGTHR: int = 32;
+export def SIGLWP: int = SIGTHR;
+export def SIGLIBRT: int = 33;
+
+export def F_DUPFD: int = 0;
+export def F_GETFD: int = 1;
+export def F_SETFD: int = 2;
+export def F_GETFL: int = 3;
+export def F_SETFL: int = 4;
+export def F_GETOWN: int = 5;
+export def F_SETOWN: int = 6;
+export def F_OGETLK: int = 7;
+export def F_OSETLK: int = 8;
+export def F_OSETLKW: int = 9;
+export def F_DUP2FD: int = 10;
+export def F_GETLK: int = 11;
+export def F_SETLK: int = 12;
+export def F_SETLKW: int = 13;
+export def F_SETLK_REMOTE: int = 14;
+export def F_READAHEAD: int = 15;
+export def F_RDAHEAD: int = 16;
+export def F_DUPFD_CLOEXEC: int = 17;
+export def F_DUP2FD_CLOEXEC: int = 18;
+export def F_ADD_SEALS: int = 19;
+export def F_GET_SEALS: int = 20;
+export def F_ISUNIONSTACK: int = 21;
+
+export def F_SEAL_SEAL: int = 0x0001;
+export def F_SEAL_SHRINK: int = 0x0002;
+export def F_SEAL_GROW: int = 0x0004;
+export def F_SEAL_WRITE: int = 0x0008;
+
+export def FD_CLOEXEC: int = 1;
+export def F_RDLCK: int = 1;
+export def F_UNLCK: int = 2;
+export def F_WRLCK: int = 3;
+export def F_UNLCKSYS: int = 4;
+export def F_CANCEL: int = 5;
+
+export def PRIO_PROCESS: int = 0;
+export def PRIO_PGRP: int = 1;
+export def PRIO_USER: int = 2;
+
+export def F_OK: int = 0;
+export def X_OK: int = 0x01;
+export def W_OK: int = 0x02;
+export def R_OK: int = 0x04;
+
+export def CLOCK_REALTIME: int = 0;
+export def CLOCK_MONOTONIC: int = 4;
+export def CLOCK_VIRTUAL: int = 1;
+export def CLOCK_PROF: int = 2;
+export def CLOCK_UPTIME: int = 5;
+export def CLOCK_UPTIME_PRECISE: int = 7;
+export def CLOCK_UPTIME_FAST: int = 8;
+export def CLOCK_REALTIME_PRECISE: int = 9;
+export def CLOCK_REALTIME_FAST: int = 10;
+export def CLOCK_MONOTONIC_PRECISE: int = 11;
+export def CLOCK_MONOTONIC_FAST: int = 12;
+export def CLOCK_SECOND: int = 13;
+export def CLOCK_THREAD_CPUTIME_ID: int = 14;
+export def CLOCK_PROCESS_CPUTIME_ID: int = 15;
diff --git a/rt/+linux/errno.ha b/rt/+linux/errno.ha
@@ -16,541 +16,541 @@ fn wrap_return(r: u64) (errno | u64) = {
// Obtains a human-friendly reading of an [[errno]] (e.g. "Operation not
// permitted").
export fn strerror(err: errno) str = {
- return switch (err: int) {
+ switch (err: int) {
case EPERM =>
- yield "Operation not permitted";
+ return "Operation not permitted";
case ENOENT =>
- yield "No such file or directory";
+ return "No such file or directory";
case ESRCH =>
- yield "No such process";
+ return "No such process";
case EINTR =>
- yield "Interrupted system call";
+ return "Interrupted system call";
case EIO =>
- yield "Input/output error";
+ return "Input/output error";
case ENXIO =>
- yield "No such device or address";
+ return "No such device or address";
case E2BIG =>
- yield "Argument list too long";
+ return "Argument list too long";
case ENOEXEC =>
- yield "Exec format error";
+ return "Exec format error";
case EBADF =>
- yield "Bad file descriptor";
+ return "Bad file descriptor";
case ECHILD =>
- yield "No child processes";
+ return "No child processes";
case EAGAIN =>
- yield "Resource temporarily unavailable";
+ return "Resource temporarily unavailable";
case ENOMEM =>
- yield "Cannot allocate memory";
+ return "Cannot allocate memory";
case EACCES =>
- yield "Permission denied";
+ return "Permission denied";
case EFAULT =>
- yield "Bad address";
+ return "Bad address";
case ENOTBLK =>
- yield "Block device required";
+ return "Block device required";
case EBUSY =>
- yield "Device or resource busy";
+ return "Device or resource busy";
case EEXIST =>
- yield "File exists";
+ return "File exists";
case EXDEV =>
- yield "Invalid cross-device link";
+ return "Invalid cross-device link";
case ENODEV =>
- yield "No such device";
+ return "No such device";
case ENOTDIR =>
- yield "Not a directory";
+ return "Not a directory";
case EISDIR =>
- yield "Is a directory";
+ return "Is a directory";
case EINVAL =>
- yield "Invalid argument";
+ return "Invalid argument";
case ENFILE =>
- yield "Too many open files in system";
+ return "Too many open files in system";
case EMFILE =>
- yield "Too many open files";
+ return "Too many open files";
case ENOTTY =>
- yield "Inappropriate ioctl for device";
+ return "Inappropriate ioctl for device";
case ETXTBSY =>
- yield "Text file busy";
+ return "Text file busy";
case EFBIG =>
- yield "File too large";
+ return "File too large";
case ENOSPC =>
- yield "No space left on device";
+ return "No space left on device";
case ESPIPE =>
- yield "Illegal seek";
+ return "Illegal seek";
case EROFS =>
- yield "Read-only file system";
+ return "Read-only file system";
case EMLINK =>
- yield "Too many links";
+ return "Too many links";
case EPIPE =>
- yield "Broken pipe";
+ return "Broken pipe";
case EDOM =>
- yield "Numerical argument out of domain";
+ return "Numerical argument out of domain";
case ERANGE =>
- yield "Numerical result out of range";
+ return "Numerical result out of range";
case EDEADLK =>
- yield "Resource deadlock avoided";
+ return "Resource deadlock avoided";
case ENAMETOOLONG =>
- yield "File name too long";
+ return "File name too long";
case ENOLCK =>
- yield "No locks available";
+ return "No locks available";
case ENOSYS =>
- yield "Function not implemented";
+ return "Function not implemented";
case ENOTEMPTY =>
- yield "Directory not empty";
+ return "Directory not empty";
case ELOOP =>
- yield "Too many levels of symbolic links";
+ return "Too many levels of symbolic links";
case ENOMSG =>
- yield "No message of desired type";
+ return "No message of desired type";
case EIDRM =>
- yield "Identifier removed";
+ return "Identifier removed";
case ECHRNG =>
- yield "Channel number out of range";
+ return "Channel number out of range";
case EL2NSYNC =>
- yield "Level 2 not synchronized";
+ return "Level 2 not synchronized";
case EL3HLT =>
- yield "Level 3 halted";
+ return "Level 3 halted";
case EL3RST =>
- yield "Level 3 reset";
+ return "Level 3 reset";
case ELNRNG =>
- yield "Link number out of range";
+ return "Link number out of range";
case EUNATCH =>
- yield "Protocol driver not attached";
+ return "Protocol driver not attached";
case ENOCSI =>
- yield "No CSI structure available";
+ return "No CSI structure available";
case EL2HLT =>
- yield "Level 2 halted";
+ return "Level 2 halted";
case EBADE =>
- yield "Invalid exchange";
+ return "Invalid exchange";
case EBADR =>
- yield "Invalid request descriptor";
+ return "Invalid request descriptor";
case EXFULL =>
- yield "Exchange full";
+ return "Exchange full";
case ENOANO =>
- yield "No anode";
+ return "No anode";
case EBADRQC =>
- yield "Invalid request code";
+ return "Invalid request code";
case EBADSLT =>
- yield "Invalid slot";
+ return "Invalid slot";
case EBFONT =>
- yield "Bad font file format";
+ return "Bad font file format";
case ENOSTR =>
- yield "Device not a stream";
+ return "Device not a stream";
case ENODATA =>
- yield "No data available";
+ return "No data available";
case ETIME =>
- yield "Timer expired";
+ return "Timer expired";
case ENOSR =>
- yield "Out of streams resources";
+ return "Out of streams resources";
case ENONET =>
- yield "Machine is not on the network";
+ return "Machine is not on the network";
case ENOPKG =>
- yield "Package not installed";
+ return "Package not installed";
case EREMOTE =>
- yield "Object is remote";
+ return "Object is remote";
case ENOLINK =>
- yield "Link has been severed";
+ return "Link has been severed";
case EADV =>
- yield "Advertise error";
+ return "Advertise error";
case ESRMNT =>
- yield "Srmount error";
+ return "Srmount error";
case ECOMM =>
- yield "Communication error on send";
+ return "Communication error on send";
case EPROTO =>
- yield "Protocol error";
+ return "Protocol error";
case EMULTIHOP =>
- yield "Multihop attempted";
+ return "Multihop attempted";
case EDOTDOT =>
- yield "RFS specific error";
+ return "RFS specific error";
case EBADMSG =>
- yield "Bad message";
+ return "Bad message";
case EOVERFLOW =>
- yield "Value too large for defined data type";
+ return "Value too large for defined data type";
case ENOTUNIQ =>
- yield "Name not unique on network";
+ return "Name not unique on network";
case EBADFD =>
- yield "File descriptor in bad state";
+ return "File descriptor in bad state";
case EREMCHG =>
- yield "Remote address changed";
+ return "Remote address changed";
case ELIBACC =>
- yield "Can not access a needed shared library";
+ return "Can not access a needed shared library";
case ELIBBAD =>
- yield "Accessing a corrupted shared library";
+ return "Accessing a corrupted shared library";
case ELIBSCN =>
- yield ".lib section in a.out corrupted";
+ return ".lib section in a.out corrupted";
case ELIBMAX =>
- yield "Attempting to link in too many shared libraries";
+ return "Attempting to link in too many shared libraries";
case ELIBEXEC =>
- yield "Cannot exec a shared library directly";
+ return "Cannot exec a shared library directly";
case EILSEQ =>
- yield "Invalid or incomplete multibyte or wide character";
+ return "Invalid or incomplete multibyte or wide character";
case ERESTART =>
- yield "Interrupted system call should be restarted";
+ return "Interrupted system call should be restarted";
case ESTRPIPE =>
- yield "Streams pipe error";
+ return "Streams pipe error";
case EUSERS =>
- yield "Too many users";
+ return "Too many users";
case ENOTSOCK =>
- yield "Socket operation on non-socket";
+ return "Socket operation on non-socket";
case EDESTADDRREQ =>
- yield "Destination address required";
+ return "Destination address required";
case EMSGSIZE =>
- yield "Message too long";
+ return "Message too long";
case EPROTOTYPE =>
- yield "Protocol wrong type for socket";
+ return "Protocol wrong type for socket";
case ENOPROTOOPT =>
- yield "Protocol not available";
+ return "Protocol not available";
case EPROTONOSUPPORT =>
- yield "Protocol not supported";
+ return "Protocol not supported";
case ESOCKTNOSUPPORT =>
- yield "Socket type not supported";
+ return "Socket type not supported";
case EOPNOTSUPP =>
- yield "Operation not supported";
+ return "Operation not supported";
case EPFNOSUPPORT =>
- yield "Protocol family not supported";
+ return "Protocol family not supported";
case EAFNOSUPPORT =>
- yield "Address family not supported by protocol";
+ return "Address family not supported by protocol";
case EADDRINUSE =>
- yield "Address already in use";
+ return "Address already in use";
case EADDRNOTAVAIL =>
- yield "Cannot assign requested address";
+ return "Cannot assign requested address";
case ENETDOWN =>
- yield "Network is down";
+ return "Network is down";
case ENETUNREACH =>
- yield "Network is unreachable";
+ return "Network is unreachable";
case ENETRESET =>
- yield "Network dropped connection on reset";
+ return "Network dropped connection on reset";
case ECONNABORTED =>
- yield "Software caused connection abort";
+ return "Software caused connection abort";
case ECONNRESET =>
- yield "Connection reset by peer";
+ return "Connection reset by peer";
case ENOBUFS =>
- yield "No buffer space available";
+ return "No buffer space available";
case EISCONN =>
- yield "Transport endpoint is already connected";
+ return "Transport endpoint is already connected";
case ENOTCONN =>
- yield "Transport endpoint is not connected";
+ return "Transport endpoint is not connected";
case ESHUTDOWN =>
- yield "Cannot send after transport endpoint shutdown";
+ return "Cannot send after transport endpoint shutdown";
case ETOOMANYREFS =>
- yield "Too many references: cannot splice";
+ return "Too many references: cannot splice";
case ETIMEDOUT =>
- yield "Connection timed out";
+ return "Connection timed out";
case ECONNREFUSED =>
- yield "Connection refused";
+ return "Connection refused";
case EHOSTDOWN =>
- yield "Host is down";
+ return "Host is down";
case EHOSTUNREACH =>
- yield "No route to host";
+ return "No route to host";
case EALREADY =>
- yield "Operation already in progress";
+ return "Operation already in progress";
case EINPROGRESS =>
- yield "Operation now in progress";
+ return "Operation now in progress";
case ESTALE =>
- yield "Stale file handle";
+ return "Stale file handle";
case EUCLEAN =>
- yield "Structure needs cleaning";
+ return "Structure needs cleaning";
case ENOTNAM =>
- yield "Not a XENIX named type file";
+ return "Not a XENIX named type file";
case ENAVAIL =>
- yield "No XENIX semaphores available";
+ return "No XENIX semaphores available";
case EISNAM =>
- yield "Is a named type file";
+ return "Is a named type file";
case EREMOTEIO =>
- yield "Remote I/O error";
+ return "Remote I/O error";
case EDQUOT =>
- yield "Disk quota exceeded";
+ return "Disk quota exceeded";
case ENOMEDIUM =>
- yield "No medium found";
+ return "No medium found";
case EMEDIUMTYPE =>
- yield "Wrong medium type";
+ return "Wrong medium type";
case ECANCELED =>
- yield "Operation canceled";
+ return "Operation canceled";
case ENOKEY =>
- yield "Required key not available";
+ return "Required key not available";
case EKEYEXPIRED =>
- yield "Key has expired";
+ return "Key has expired";
case EKEYREVOKED =>
- yield "Key has been revoked";
+ return "Key has been revoked";
case EKEYREJECTED =>
- yield "Key was rejected by service";
+ return "Key was rejected by service";
case EOWNERDEAD =>
- yield "Owner died";
+ return "Owner died";
case ENOTRECOVERABLE =>
- yield "State not recoverable";
+ return "State not recoverable";
case ERFKILL =>
- yield "Operation not possible due to RF-kill";
+ return "Operation not possible due to RF-kill";
case EHWPOISON =>
- yield "Memory page has hardware error";
+ return "Memory page has hardware error";
case =>
- yield "Unknown Linux error code"; // TODO: snprintf to add errno?
+ return "[unknown errno]"; // TODO: snprintf to add errno?
};
};
// Gets the programmer-friendly name for an [[errno]] (e.g. EPERM).
export fn errname(err: errno) str = {
- return switch (err: int) {
+ switch (err: int) {
case EPERM =>
- yield "EPERM";
+ return "EPERM";
case ENOENT =>
- yield "ENOENT";
+ return "ENOENT";
case ESRCH =>
- yield "ESRCH";
+ return "ESRCH";
case EINTR =>
- yield "EINTR";
+ return "EINTR";
case EIO =>
- yield "EIO";
+ return "EIO";
case ENXIO =>
- yield "ENXIO";
+ return "ENXIO";
case E2BIG =>
- yield "E2BIG";
+ return "E2BIG";
case ENOEXEC =>
- yield "ENOEXEC";
+ return "ENOEXEC";
case EBADF =>
- yield "EBADF";
+ return "EBADF";
case ECHILD =>
- yield "ECHILD";
+ return "ECHILD";
case EAGAIN =>
- yield "EAGAIN";
+ return "EAGAIN";
case ENOMEM =>
- yield "ENOMEM";
+ return "ENOMEM";
case EACCES =>
- yield "EACCES";
+ return "EACCES";
case EFAULT =>
- yield "EFAULT";
+ return "EFAULT";
case ENOTBLK =>
- yield "ENOTBLK";
+ return "ENOTBLK";
case EBUSY =>
- yield "EBUSY";
+ return "EBUSY";
case EEXIST =>
- yield "EEXIST";
+ return "EEXIST";
case EXDEV =>
- yield "EXDEV";
+ return "EXDEV";
case ENODEV =>
- yield "ENODEV";
+ return "ENODEV";
case ENOTDIR =>
- yield "ENOTDIR";
+ return "ENOTDIR";
case EISDIR =>
- yield "EISDIR";
+ return "EISDIR";
case EINVAL =>
- yield "EINVAL";
+ return "EINVAL";
case ENFILE =>
- yield "ENFILE";
+ return "ENFILE";
case EMFILE =>
- yield "EMFILE";
+ return "EMFILE";
case ENOTTY =>
- yield "ENOTTY";
+ return "ENOTTY";
case ETXTBSY =>
- yield "ETXTBSY";
+ return "ETXTBSY";
case EFBIG =>
- yield "EFBIG";
+ return "EFBIG";
case ENOSPC =>
- yield "ENOSPC";
+ return "ENOSPC";
case ESPIPE =>
- yield "ESPIPE";
+ return "ESPIPE";
case EROFS =>
- yield "EROFS";
+ return "EROFS";
case EMLINK =>
- yield "EMLINK";
+ return "EMLINK";
case EPIPE =>
- yield "EPIPE";
+ return "EPIPE";
case EDOM =>
- yield "EDOM";
+ return "EDOM";
case ERANGE =>
- yield "ERANGE";
+ return "ERANGE";
case EDEADLK =>
- yield "EDEADLK";
+ return "EDEADLK";
case ENAMETOOLONG =>
- yield "ENAMETOOLONG";
+ return "ENAMETOOLONG";
case ENOLCK =>
- yield "ENOLCK";
+ return "ENOLCK";
case ENOSYS =>
- yield "ENOSYS";
+ return "ENOSYS";
case ENOTEMPTY =>
- yield "ENOTEMPTY";
+ return "ENOTEMPTY";
case ELOOP =>
- yield "ELOOP";
+ return "ELOOP";
case ENOMSG =>
- yield "ENOMSG";
+ return "ENOMSG";
case EIDRM =>
- yield "EIDRM";
+ return "EIDRM";
case ECHRNG =>
- yield "ECHRNG";
+ return "ECHRNG";
case EL2NSYNC =>
- yield "EL2NSYNC";
+ return "EL2NSYNC";
case EL3HLT =>
- yield "EL3HLT";
+ return "EL3HLT";
case EL3RST =>
- yield "EL3RST";
+ return "EL3RST";
case ELNRNG =>
- yield "ELNRNG";
+ return "ELNRNG";
case EUNATCH =>
- yield "EUNATCH";
+ return "EUNATCH";
case ENOCSI =>
- yield "ENOCSI";
+ return "ENOCSI";
case EL2HLT =>
- yield "EL2HLT";
+ return "EL2HLT";
case EBADE =>
- yield "EBADE";
+ return "EBADE";
case EBADR =>
- yield "EBADR";
+ return "EBADR";
case EXFULL =>
- yield "EXFULL";
+ return "EXFULL";
case ENOANO =>
- yield "ENOANO";
+ return "ENOANO";
case EBADRQC =>
- yield "EBADRQC";
+ return "EBADRQC";
case EBADSLT =>
- yield "EBADSLT";
+ return "EBADSLT";
case EBFONT =>
- yield "EBFONT";
+ return "EBFONT";
case ENOSTR =>
- yield "ENOSTR";
+ return "ENOSTR";
case ENODATA =>
- yield "ENODATA";
+ return "ENODATA";
case ETIME =>
- yield "ETIME";
+ return "ETIME";
case ENOSR =>
- yield "ENOSR";
+ return "ENOSR";
case ENONET =>
- yield "ENONET";
+ return "ENONET";
case ENOPKG =>
- yield "ENOPKG";
+ return "ENOPKG";
case EREMOTE =>
- yield "EREMOTE";
+ return "EREMOTE";
case ENOLINK =>
- yield "ENOLINK";
+ return "ENOLINK";
case EADV =>
- yield "EADV";
+ return "EADV";
case ESRMNT =>
- yield "ESRMNT";
+ return "ESRMNT";
case ECOMM =>
- yield "ECOMM";
+ return "ECOMM";
case EPROTO =>
- yield "EPROTO";
+ return "EPROTO";
case EMULTIHOP =>
- yield "EMULTIHOP";
+ return "EMULTIHOP";
case EDOTDOT =>
- yield "EDOTDOT";
+ return "EDOTDOT";
case EBADMSG =>
- yield "EBADMSG";
+ return "EBADMSG";
case EOVERFLOW =>
- yield "EOVERFLOW";
+ return "EOVERFLOW";
case ENOTUNIQ =>
- yield "ENOTUNIQ";
+ return "ENOTUNIQ";
case EBADFD =>
- yield "EBADFD";
+ return "EBADFD";
case EREMCHG =>
- yield "EREMCHG";
+ return "EREMCHG";
case ELIBACC =>
- yield "ELIBACC";
+ return "ELIBACC";
case ELIBBAD =>
- yield "ELIBBAD";
+ return "ELIBBAD";
case ELIBSCN =>
- yield "ELIBSCN";
+ return "ELIBSCN";
case ELIBMAX =>
- yield "ELIBMAX";
+ return "ELIBMAX";
case ELIBEXEC =>
- yield "ELIBEXEC";
+ return "ELIBEXEC";
case EILSEQ =>
- yield "EILSEQ";
+ return "EILSEQ";
case ERESTART =>
- yield "ERESTART";
+ return "ERESTART";
case ESTRPIPE =>
- yield "ESTRPIPE";
+ return "ESTRPIPE";
case EUSERS =>
- yield "EUSERS";
+ return "EUSERS";
case ENOTSOCK =>
- yield "ENOTSOCK";
+ return "ENOTSOCK";
case EDESTADDRREQ =>
- yield "EDESTADDRREQ";
+ return "EDESTADDRREQ";
case EMSGSIZE =>
- yield "EMSGSIZE";
+ return "EMSGSIZE";
case EPROTOTYPE =>
- yield "EPROTOTYPE";
+ return "EPROTOTYPE";
case ENOPROTOOPT =>
- yield "ENOPROTOOPT";
+ return "ENOPROTOOPT";
case EPROTONOSUPPORT =>
- yield "EPROTONOSUPPORT";
+ return "EPROTONOSUPPORT";
case ESOCKTNOSUPPORT =>
- yield "ESOCKTNOSUPPORT";
+ return "ESOCKTNOSUPPORT";
case EOPNOTSUPP =>
- yield "EOPNOTSUPP";
+ return "EOPNOTSUPP";
case EPFNOSUPPORT =>
- yield "EPFNOSUPPORT";
+ return "EPFNOSUPPORT";
case EAFNOSUPPORT =>
- yield "EAFNOSUPPORT";
+ return "EAFNOSUPPORT";
case EADDRINUSE =>
- yield "EADDRINUSE";
+ return "EADDRINUSE";
case EADDRNOTAVAIL =>
- yield "EADDRNOTAVAIL";
+ return "EADDRNOTAVAIL";
case ENETDOWN =>
- yield "ENETDOWN";
+ return "ENETDOWN";
case ENETUNREACH =>
- yield "ENETUNREACH";
+ return "ENETUNREACH";
case ENETRESET =>
- yield "ENETRESET";
+ return "ENETRESET";
case ECONNABORTED =>
- yield "ECONNABORTED";
+ return "ECONNABORTED";
case ECONNRESET =>
- yield "ECONNRESET";
+ return "ECONNRESET";
case ENOBUFS =>
- yield "ENOBUFS";
+ return "ENOBUFS";
case EISCONN =>
- yield "EISCONN";
+ return "EISCONN";
case ENOTCONN =>
- yield "ENOTCONN";
+ return "ENOTCONN";
case ESHUTDOWN =>
- yield "ESHUTDOWN";
+ return "ESHUTDOWN";
case ETOOMANYREFS =>
- yield "ETOOMANYREFS";
+ return "ETOOMANYREFS";
case ETIMEDOUT =>
- yield "ETIMEDOUT";
+ return "ETIMEDOUT";
case ECONNREFUSED =>
- yield "ECONNREFUSED";
+ return "ECONNREFUSED";
case EHOSTDOWN =>
- yield "EHOSTDOWN";
+ return "EHOSTDOWN";
case EHOSTUNREACH =>
- yield "EHOSTUNREACH";
+ return "EHOSTUNREACH";
case EALREADY =>
- yield "EALREADY";
+ return "EALREADY";
case EINPROGRESS =>
- yield "EINPROGRESS";
+ return "EINPROGRESS";
case ESTALE =>
- yield "ESTALE";
+ return "ESTALE";
case EUCLEAN =>
- yield "EUCLEAN";
+ return "EUCLEAN";
case ENOTNAM =>
- yield "ENOTNAM";
+ return "ENOTNAM";
case ENAVAIL =>
- yield "ENAVAIL";
+ return "ENAVAIL";
case EISNAM =>
- yield "EISNAM";
+ return "EISNAM";
case EREMOTEIO =>
- yield "EREMOTEIO";
+ return "EREMOTEIO";
case EDQUOT =>
- yield "EDQUOT";
+ return "EDQUOT";
case ENOMEDIUM =>
- yield "ENOMEDIUM";
+ return "ENOMEDIUM";
case EMEDIUMTYPE =>
- yield "EMEDIUMTYPE";
+ return "EMEDIUMTYPE";
case ECANCELED =>
- yield "ECANCELED";
+ return "ECANCELED";
case ENOKEY =>
- yield "ENOKEY";
+ return "ENOKEY";
case EKEYEXPIRED =>
- yield "EKEYEXPIRED";
+ return "EKEYEXPIRED";
case EKEYREVOKED =>
- yield "EKEYREVOKED";
+ return "EKEYREVOKED";
case EKEYREJECTED =>
- yield "EKEYREJECTED";
+ return "EKEYREJECTED";
case EOWNERDEAD =>
- yield "EOWNERDEAD";
+ return "EOWNERDEAD";
case ENOTRECOVERABLE =>
- yield "ENOTRECOVERABLE";
+ return "ENOTRECOVERABLE";
case ERFKILL =>
- yield "ERFKILL";
+ return "ERFKILL";
case EHWPOISON =>
- yield "EHWPOISON";
+ return "EHWPOISON";
case =>
- yield "[unknown errno]"; // TODO: snprintf to add errno?
+ return "[unknown errno]"; // TODO: snprintf to add errno?
};
};
diff --git a/rt/+linux/segmalloc.ha b/rt/+linux/segmalloc.ha
@@ -18,9 +18,3 @@ fn segfree(p: *void, s: size) void = {
case void => void;
};
};
-
-// Marks a segment as writable and drops the execute bit.
-fn segwrite(seg: *void, n: size) void = mprotect(seg, n, PROT_READ | PROT_WRITE)!;
-
-// Marks a segment as executable and drops the write bit.
-fn segexec(seg: *void, n: size) void = mprotect(seg, n, PROT_READ | PROT_EXEC)!;
diff --git a/rt/+linux/syscalls.ha b/rt/+linux/syscalls.ha
@@ -369,7 +369,6 @@ export fn getrandom(buf: *void, bufln: size, flags: uint) (size | errno) = {
buf: uintptr: u64, bufln: u64, flags: u64))?: size;
};
-// TODO: Implement me with VDSO
export fn clock_gettime(clock_id: int, tp: *timespec) (void | errno) = {
wrap_return(syscall2(SYS_clock_gettime,
clock_id: u64, tp: uintptr: u64))?;
diff --git a/rt/+test/+freebsd.ha b/rt/+test/+freebsd.ha
@@ -0,0 +1,13 @@
+let start: timespec = timespec { ... };
+
+fn time_start() void = {
+ clock_gettime(CLOCK_MONOTONIC, &start) as void;
+};
+
+// Returns elapsed time as (seconds, milliseconds)
+fn time_stop() (size, size) = {
+ let end: timespec = timespec { ... };
+ clock_gettime(CLOCK_MONOTONIC, &end) as void;
+ return ((end.tv_sec - start.tv_sec): size,
+ (end.tv_nsec - start.tv_nsec): size / 10000z);
+};
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -14,24 +14,50 @@
srcdir="$(dirname "$0")"
eval ". $srcdir/gen-stdlib.sh"
+all_platforms="linux
+freebsd"
+
gensrcs_rt() {
gen_srcs -plinux rt \
- '+linux/abort.ha' \
- '+linux/env.ha' \
- '+linux/errno.ha' \
- '+linux/types.ha' \
- '+linux/segmalloc.ha' \
- '+linux/platformstart.ha' \
- '+linux/prctl.ha' \
- '+linux/+$(ARCH).ha' \
- '+linux/syscallno+$(ARCH).ha' \
- '+linux/syscalls.ha' \
- '+linux/signal.ha' \
- '+linux/stat.ha' \
- '+linux/socket.ha' \
- '+$(ARCH)/jmp.ha' \
- '+$(ARCH)/backtrace.ha' \
- 'types_arch+$(ARCH).ha' \
+ +linux/abort.ha \
+ +linux/env.ha \
+ +linux/errno.ha \
+ +linux/types.ha \
+ +linux/segmalloc.ha \
+ +linux/platformstart.ha \
+ +linux/prctl.ha \
+ +linux/'+$(ARCH)'.ha \
+ +linux/syscallno+'$(ARCH)'.ha \
+ +linux/syscalls.ha \
+ +linux/signal.ha \
+ +linux/stat.ha \
+ +linux/socket.ha \
+ '+$(ARCH)'/jmp.ha \
+ '+$(ARCH)'/backtrace.ha \
+ types_arch+'$(ARCH)'.ha \
+ ensure.ha \
+ jmp.ha \
+ malloc.ha \
+ memcpy.ha \
+ memmove.ha \
+ memset.ha \
+ strcmp.ha \
+ types.ha \
+ $*
+ gen_srcs -pfreebsd rt \
+ +freebsd/abort.ha \
+ +freebsd/env.ha \
+ +freebsd/errno.ha \
+ +freebsd/platformstart.ha \
+ +freebsd/segmalloc.ha \
+ +freebsd/signal.ha \
+ +freebsd/socket.ha \
+ +freebsd/syscallno.ha \
+ +freebsd/syscalls.ha \
+ +freebsd/types.ha \
+ +'$(ARCH)'/jmp.ha \
+ +'$(ARCH)'/backtrace.ha \
+ types_arch+'$(ARCH)'.ha \
ensure.ha \
jmp.ha \
malloc.ha \
@@ -61,6 +87,7 @@ rt() {
+test/ztos.ha
fi
gen_ssa -plinux rt
+ gen_ssa -pfreebsd rt
cat <<EOF
\$($cache)/rt/start.o: \$(STDLIB)/rt/+\$(PLATFORM)/start+\$(ARCH).s
@printf 'AS \t\$@\n'
@@ -103,8 +130,14 @@ ${stdlib}_asm=\$($cache)/rt/syscall.o \\
@printf 'AR\t\$@\n'
@\$(AR) -csr \$@ \$($cache)/rt/rt-linux.o \$(${stdlib}_asm)
+\$($cache)/rt/rt-freebsd.a: \$($cache)/rt/rt-freebsd.o \$(${stdlib}_asm)
+ @printf 'AR\t\$@\n'
+ @\$(AR) -csr \$@ \$($cache)/rt/rt-freebsd.o \$(${stdlib}_asm)
+
${stdlib}_rt=\$($cache)/rt/rt-\$(PLATFORM).a
-hare_${stdlib}_deps+=\$(${stdlib}_rt)
+${stdlib}_deps_linux+=\$(${stdlib}_rt)
+${stdlib}_deps_freebsd+=\$(${stdlib}_rt)
+${stdlib}_deps_any+=\$(${stdlib}_rt)
EOF
}
@@ -184,6 +217,11 @@ crypto_random() {
+linux.ha \
random.ha
gen_ssa -plinux crypto::random rt io errors
+
+ gen_srcs -pfreebsd crypto::random \
+ +freebsd.ha \
+ random.ha
+ gen_ssa -pfreebsd crypto::random rt io errors
}
gensrcs_crypto_sha256() {
@@ -557,6 +595,20 @@ gensrcs_io() {
tee.ha \
types.ha \
$*
+ gen_srcs -pfreebsd io \
+ 'arch+$(ARCH).ha' \
+ println+freebsd.ha \
+ +freebsd/file.ha \
+ copy.ha \
+ drain.ha \
+ empty.ha \
+ filestream.ha \
+ handle.ha \
+ limit.ha \
+ stream.ha \
+ tee.ha \
+ types.ha \
+ $*
}
io() {
@@ -570,6 +622,7 @@ io() {
+test/stream.ha
fi
gen_ssa -plinux io strings errors
+ gen_ssa -pfreebsd io strings errors
}
iobus_io_uring() {
@@ -633,6 +686,12 @@ net() {
errors.ha \
listener.ha
gen_ssa -plinux net io os strings net::ip errors rt fmt
+
+ gen_srcs -pfreebsd net \
+ +freebsd.ha \
+ errors.ha \
+ listener.ha
+ gen_ssa -pfreebsd net io os strings net::ip errors rt fmt
}
net_dial() {
@@ -658,8 +717,12 @@ net_dns() {
gensrcs_net_ip() {
gen_srcs -plinux net::ip \
- ip.ha \
+linux.ha \
+ ip.ha \
+ $*
+ gen_srcs -pfreebsd net::ip \
+ +freebsd.ha \
+ ip.ha \
$*
}
@@ -672,6 +735,7 @@ net_ip() {
+test.ha
fi
gen_ssa -plinux net::ip bytes io strconv strings strio fmt
+ gen_ssa -pfreebsd net::ip bytes io strconv strings strio fmt
}
net_tcp() {
@@ -680,6 +744,12 @@ net_tcp() {
listener.ha \
options.ha
gen_ssa -plinux net::tcp io net net::ip os rt
+
+ gen_srcs -pfreebsd net::tcp \
+ +freebsd.ha \
+ listener.ha \
+ options.ha
+ gen_ssa -pfreebsd net::tcp io net net::ip os rt
}
net_udp() {
@@ -687,6 +757,11 @@ net_udp() {
+linux.ha \
options.ha
gen_ssa -plinux net::udp net net::ip errors rt os io
+
+ gen_srcs -pfreebsd net::udp \
+ +freebsd.ha \
+ options.ha
+ gen_ssa -pfreebsd net::udp net net::ip errors rt os io
}
net_unix() {
@@ -697,6 +772,14 @@ net_unix() {
listener.ha \
options.ha
gen_ssa -plinux net::unix net errors os io strings types fmt net::dial
+
+ gen_srcs -pfreebsd net::unix \
+ +freebsd.ha \
+ addr.ha \
+ dial.ha \
+ listener.ha \
+ options.ha
+ gen_ssa -pfreebsd net::unix net errors os io strings types fmt net::dial
}
math_random() {
@@ -714,6 +797,15 @@ os() {
+linux/fs.ha \
fs.ha
gen_ssa -plinux os io strings types fs encoding::utf8 bytes bufio errors
+
+ gen_srcs -pfreebsd os \
+ +freebsd/environ.ha \
+ +freebsd/exit.ha \
+ +freebsd/dirfdfs.ha \
+ +freebsd/stdfd.ha \
+ +freebsd/fs.ha \
+ fs.ha
+ gen_ssa -pfreebsd os io strings types fs encoding::utf8 bytes bufio errors
}
os_exec() {
@@ -723,6 +815,13 @@ os_exec() {
types.ha \
cmd.ha
gen_ssa -plinux os::exec os strings fmt bytes path errors
+
+ gen_srcs -pfreebsd os::exec \
+ exec+freebsd.ha \
+ process+freebsd.ha \
+ types.ha \
+ cmd.ha
+ gen_ssa -pfreebsd os::exec os strings fmt bytes path errors
}
path() {
@@ -814,6 +913,10 @@ temp() {
gen_srcs -plinux temp +linux.ha
gen_ssa -plinux temp \
crypto::random encoding::hex fs io os path strio fmt strings
+
+ gen_srcs -pfreebsd temp +freebsd.ha
+ gen_ssa -pfreebsd temp \
+ crypto::random encoding::hex fs io os path strio fmt strings
}
time() {
@@ -823,6 +926,11 @@ time() {
arithm.ha \
types.ha
gen_ssa -plinux time linux::vdso
+ gen_srcs -pfreebsd time \
+ +freebsd/functions.ha \
+ arithm.ha \
+ types.ha
+ gen_ssa -pfreebsd time
}
gensrcs_types() {
@@ -854,6 +962,14 @@ unix() {
getuid.ha \
setuid.ha
gen_ssa -plinux unix errors fs
+
+ gen_srcs -pfreebsd unix \
+ +freebsd/nice.ha \
+ +freebsd/pipe.ha \
+ +freebsd/umask.ha \
+ getuid.ha \
+ setuid.ha
+ gen_ssa -pfreebsd unix errors fs
}
unix_hosts() {
@@ -873,6 +989,9 @@ unix_passwd() {
unix_poll() {
gen_srcs -plinux unix::poll +linux.ha
gen_ssa -plinux unix::poll rt errors time
+
+ gen_srcs -pfreebsd unix::poll +freebsd.ha
+ gen_ssa -pfreebsd unix::poll rt errors time
}
unix_resolvconf() {
@@ -888,6 +1007,13 @@ unix_tty() {
+linux/open.ha \
+linux/winsize.ha
gen_ssa -plinux unix::tty rt fs io os
+
+ gen_srcs -pfreebsd unix::tty \
+ types.ha \
+ +freebsd/isatty.ha \
+ +freebsd/open.ha \
+ +freebsd/winsize.ha
+ gen_ssa -pfreebsd unix::tty rt fs io os
}
uuid() {
@@ -908,7 +1034,7 @@ compress::flate
compress::zlib
crypto::blake2b
crypto::math
-crypto::random linux
+crypto::random linux freebsd
crypto::md5
crypto::sha1
crypto::sha256
@@ -940,38 +1066,38 @@ hash::crc16
hash::crc32
hash::crc64
hash::fnv
-io linux
+io linux freebsd
iobus::io_uring linux
linux linux
linux::signalfd linux
linux::io_uring linux
linux::vdso linux
math
-net linux
+net linux freebsd
net::dial
net::dns
-net::ip linux
-net::tcp linux
-net::udp linux
-net::unix linux
+net::ip linux freebsd
+net::tcp linux freebsd
+net::udp linux freebsd
+net::unix linux freebsd
math::random
-os linux
-os::exec linux
+os linux freebsd
+os::exec linux freebsd
path
slice
sort
strconv
strings
strio
-temp linux
-time linux
+temp linux freebsd
+time linux freebsd
types
-unix linux
+unix linux freebsd
unix::hosts
unix::passwd
-unix::poll linux
+unix::poll linux freebsd
unix::resolvconf
-unix::tty linux
+unix::tty linux freebsd
uuid"
stdlib() {
rt
diff --git a/scripts/gen-stdlib.sh b/scripts/gen-stdlib.sh
@@ -5,7 +5,7 @@ mod_file() {
printf '%s\n' "$1" | tr -s '::' '_'
}
mod_var() {
- printf '%s_%s\n' "$stdlib" "$1" | tr -s '::' '_'
+ printf '%s_%s_%s\n' "$stdlib" "$1" "$2" | tr -s '::' '_'
}
gen_srcs() {
@@ -28,10 +28,10 @@ gen_srcs() {
shift
path="$(mod_path "$mod")"
- var="$(mod_var "$mod")"
+ var="$(mod_var "$mod" "$platform")"
printf '# %s (+%s)\n' "$mod" "$platform"
- printf '%s_%s_srcs= \\\n' "$var" "$platform"
+ printf '%s_srcs= \\\n' "$var"
while [ $# -ne 0 ]
do
if [ $# -eq 1 ]
@@ -65,12 +65,12 @@ gen_ssa() {
path=$(mod_path "$mod")
file=$(mod_file "$mod")
- var=$(mod_var "$mod")
+ var=$(mod_var "$mod" "$platform")
- printf "\$($cache)/$path/$file-$platform.ssa: \$(${var}_${platform}_srcs) \$(${stdlib}_rt)"
+ printf "\$($cache)/$path/$file-$platform.ssa: \$(${var}_srcs) \$(${stdlib}_rt)"
for dep in $*
do
- printf ' $(%s)' "$(mod_var "$dep")"
+ printf ' $(%s)' "$(mod_var "$dep" \$"(PLATFORM)")"
done
printf '\n'
@@ -78,7 +78,7 @@ gen_ssa() {
@printf 'HAREC \t\$@\n'
@mkdir -p \$($cache)/$path
@HARECACHE=\$($cache) \$(HAREC) \$($flags) -o \$@ -N$mod \\
- -t\$($cache)/$path/$file.td \$(${var}_${platform}_srcs)
+ -t\$($cache)/$path/$file.td \$(${var}_srcs)
EOF
}
@@ -104,9 +104,17 @@ gen_lib() {
mod="$1"
path=$(mod_path "$mod")
file=$(mod_file "$mod")
- var=$(mod_var "$mod")
+ var=$(mod_var "$mod" "$platform")
printf "%s=\$(%s)/%s/%s-%s.o\n" "$var" "$cache" "$path" "$file" "$platform"
- printf 'hare_%s_deps+=$(%s)\n\n' "$stdlib" "$var"
+ printf '%s_deps_%s+=$(%s)\n' "$stdlib" "$platform" "$var"
+ if [ "$platform" = "any" ]
+ then
+ for p in $all_platforms
+ do
+ printf '%s=$(%s)\n' "$(mod_var "$mod" "$p")" "$var"
+ done
+ fi
+ printf '\n'
}
genrules() {
diff --git a/scripts/platform b/scripts/platform
@@ -4,6 +4,9 @@ case $(uname) in
Linux)
platform="linux"
;;
+ FreeBSD)
+ platform="freebsd"
+ ;;
*)
printf "Warning: unknown target %s\n" "$(uname)" >&2
platform="unknown"
diff --git a/stdlib.mk b/stdlib.mk
@@ -30,12 +30,44 @@ stdlib_rt_linux_srcs= \
$(STDLIB)/rt/abort.ha \
$(STDLIB)/rt/start.ha
+# rt (+freebsd)
+stdlib_rt_freebsd_srcs= \
+ $(STDLIB)/rt/+freebsd/abort.ha \
+ $(STDLIB)/rt/+freebsd/env.ha \
+ $(STDLIB)/rt/+freebsd/errno.ha \
+ $(STDLIB)/rt/+freebsd/platformstart.ha \
+ $(STDLIB)/rt/+freebsd/segmalloc.ha \
+ $(STDLIB)/rt/+freebsd/signal.ha \
+ $(STDLIB)/rt/+freebsd/socket.ha \
+ $(STDLIB)/rt/+freebsd/syscallno.ha \
+ $(STDLIB)/rt/+freebsd/syscalls.ha \
+ $(STDLIB)/rt/+freebsd/types.ha \
+ $(STDLIB)/rt/+$(ARCH)/jmp.ha \
+ $(STDLIB)/rt/+$(ARCH)/backtrace.ha \
+ $(STDLIB)/rt/types_arch+$(ARCH).ha \
+ $(STDLIB)/rt/ensure.ha \
+ $(STDLIB)/rt/jmp.ha \
+ $(STDLIB)/rt/malloc.ha \
+ $(STDLIB)/rt/memcpy.ha \
+ $(STDLIB)/rt/memmove.ha \
+ $(STDLIB)/rt/memset.ha \
+ $(STDLIB)/rt/strcmp.ha \
+ $(STDLIB)/rt/types.ha \
+ $(STDLIB)/rt/abort.ha \
+ $(STDLIB)/rt/start.ha
+
$(HARECACHE)/rt/rt-linux.ssa: $(stdlib_rt_linux_srcs) $(stdlib_rt)
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/rt
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nrt \
-t$(HARECACHE)/rt/rt.td $(stdlib_rt_linux_srcs)
+$(HARECACHE)/rt/rt-freebsd.ssa: $(stdlib_rt_freebsd_srcs) $(stdlib_rt)
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/rt
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nrt \
+ -t$(HARECACHE)/rt/rt.td $(stdlib_rt_freebsd_srcs)
+
$(HARECACHE)/rt/start.o: $(STDLIB)/rt/+$(PLATFORM)/start+$(ARCH).s
@printf 'AS \t$@\n'
@mkdir -p $(HARECACHE)/rt
@@ -77,303 +109,471 @@ $(HARECACHE)/rt/rt-linux.a: $(HARECACHE)/rt/rt-linux.o $(stdlib_asm)
@printf 'AR\t$@\n'
@$(AR) -csr $@ $(HARECACHE)/rt/rt-linux.o $(stdlib_asm)
+$(HARECACHE)/rt/rt-freebsd.a: $(HARECACHE)/rt/rt-freebsd.o $(stdlib_asm)
+ @printf 'AR\t$@\n'
+ @$(AR) -csr $@ $(HARECACHE)/rt/rt-freebsd.o $(stdlib_asm)
+
stdlib_rt=$(HARECACHE)/rt/rt-$(PLATFORM).a
-hare_stdlib_deps+=$(stdlib_rt)
+stdlib_deps_linux+=$(stdlib_rt)
+stdlib_deps_freebsd+=$(stdlib_rt)
+stdlib_deps_any+=$(stdlib_rt)
# gen_lib ascii (any)
-stdlib_ascii=$(HARECACHE)/ascii/ascii-any.o
-hare_stdlib_deps+=$(stdlib_ascii)
+stdlib_ascii_any=$(HARECACHE)/ascii/ascii-any.o
+stdlib_deps_any+=$(stdlib_ascii_any)
+stdlib_ascii_linux=$(stdlib_ascii_any)
+stdlib_ascii_freebsd=$(stdlib_ascii_any)
# gen_lib bufio (any)
-stdlib_bufio=$(HARECACHE)/bufio/bufio-any.o
-hare_stdlib_deps+=$(stdlib_bufio)
+stdlib_bufio_any=$(HARECACHE)/bufio/bufio-any.o
+stdlib_deps_any+=$(stdlib_bufio_any)
+stdlib_bufio_linux=$(stdlib_bufio_any)
+stdlib_bufio_freebsd=$(stdlib_bufio_any)
# gen_lib bytes (any)
-stdlib_bytes=$(HARECACHE)/bytes/bytes-any.o
-hare_stdlib_deps+=$(stdlib_bytes)
+stdlib_bytes_any=$(HARECACHE)/bytes/bytes-any.o
+stdlib_deps_any+=$(stdlib_bytes_any)
+stdlib_bytes_linux=$(stdlib_bytes_any)
+stdlib_bytes_freebsd=$(stdlib_bytes_any)
# gen_lib compress::flate (any)
-stdlib_compress_flate=$(HARECACHE)/compress/flate/compress_flate-any.o
-hare_stdlib_deps+=$(stdlib_compress_flate)
+stdlib_compress_flate_any=$(HARECACHE)/compress/flate/compress_flate-any.o
+stdlib_deps_any+=$(stdlib_compress_flate_any)
+stdlib_compress_flate_linux=$(stdlib_compress_flate_any)
+stdlib_compress_flate_freebsd=$(stdlib_compress_flate_any)
# gen_lib compress::zlib (any)
-stdlib_compress_zlib=$(HARECACHE)/compress/zlib/compress_zlib-any.o
-hare_stdlib_deps+=$(stdlib_compress_zlib)
+stdlib_compress_zlib_any=$(HARECACHE)/compress/zlib/compress_zlib-any.o
+stdlib_deps_any+=$(stdlib_compress_zlib_any)
+stdlib_compress_zlib_linux=$(stdlib_compress_zlib_any)
+stdlib_compress_zlib_freebsd=$(stdlib_compress_zlib_any)
# gen_lib crypto::blake2b (any)
-stdlib_crypto_blake2b=$(HARECACHE)/crypto/blake2b/crypto_blake2b-any.o
-hare_stdlib_deps+=$(stdlib_crypto_blake2b)
+stdlib_crypto_blake2b_any=$(HARECACHE)/crypto/blake2b/crypto_blake2b-any.o
+stdlib_deps_any+=$(stdlib_crypto_blake2b_any)
+stdlib_crypto_blake2b_linux=$(stdlib_crypto_blake2b_any)
+stdlib_crypto_blake2b_freebsd=$(stdlib_crypto_blake2b_any)
# gen_lib crypto::math (any)
-stdlib_crypto_math=$(HARECACHE)/crypto/math/crypto_math-any.o
-hare_stdlib_deps+=$(stdlib_crypto_math)
+stdlib_crypto_math_any=$(HARECACHE)/crypto/math/crypto_math-any.o
+stdlib_deps_any+=$(stdlib_crypto_math_any)
+stdlib_crypto_math_linux=$(stdlib_crypto_math_any)
+stdlib_crypto_math_freebsd=$(stdlib_crypto_math_any)
# gen_lib crypto::random (linux)
-stdlib_crypto_random=$(HARECACHE)/crypto/random/crypto_random-linux.o
-hare_stdlib_deps+=$(stdlib_crypto_random)
+stdlib_crypto_random_linux=$(HARECACHE)/crypto/random/crypto_random-linux.o
+stdlib_deps_linux+=$(stdlib_crypto_random_linux)
+
+# gen_lib crypto::random (freebsd)
+stdlib_crypto_random_freebsd=$(HARECACHE)/crypto/random/crypto_random-freebsd.o
+stdlib_deps_freebsd+=$(stdlib_crypto_random_freebsd)
# gen_lib crypto::md5 (any)
-stdlib_crypto_md5=$(HARECACHE)/crypto/md5/crypto_md5-any.o
-hare_stdlib_deps+=$(stdlib_crypto_md5)
+stdlib_crypto_md5_any=$(HARECACHE)/crypto/md5/crypto_md5-any.o
+stdlib_deps_any+=$(stdlib_crypto_md5_any)
+stdlib_crypto_md5_linux=$(stdlib_crypto_md5_any)
+stdlib_crypto_md5_freebsd=$(stdlib_crypto_md5_any)
# gen_lib crypto::sha1 (any)
-stdlib_crypto_sha1=$(HARECACHE)/crypto/sha1/crypto_sha1-any.o
-hare_stdlib_deps+=$(stdlib_crypto_sha1)
+stdlib_crypto_sha1_any=$(HARECACHE)/crypto/sha1/crypto_sha1-any.o
+stdlib_deps_any+=$(stdlib_crypto_sha1_any)
+stdlib_crypto_sha1_linux=$(stdlib_crypto_sha1_any)
+stdlib_crypto_sha1_freebsd=$(stdlib_crypto_sha1_any)
# gen_lib crypto::sha256 (any)
-stdlib_crypto_sha256=$(HARECACHE)/crypto/sha256/crypto_sha256-any.o
-hare_stdlib_deps+=$(stdlib_crypto_sha256)
+stdlib_crypto_sha256_any=$(HARECACHE)/crypto/sha256/crypto_sha256-any.o
+stdlib_deps_any+=$(stdlib_crypto_sha256_any)
+stdlib_crypto_sha256_linux=$(stdlib_crypto_sha256_any)
+stdlib_crypto_sha256_freebsd=$(stdlib_crypto_sha256_any)
# gen_lib crypto::sha512 (any)
-stdlib_crypto_sha512=$(HARECACHE)/crypto/sha512/crypto_sha512-any.o
-hare_stdlib_deps+=$(stdlib_crypto_sha512)
+stdlib_crypto_sha512_any=$(HARECACHE)/crypto/sha512/crypto_sha512-any.o
+stdlib_deps_any+=$(stdlib_crypto_sha512_any)
+stdlib_crypto_sha512_linux=$(stdlib_crypto_sha512_any)
+stdlib_crypto_sha512_freebsd=$(stdlib_crypto_sha512_any)
# gen_lib dirs (any)
-stdlib_dirs=$(HARECACHE)/dirs/dirs-any.o
-hare_stdlib_deps+=$(stdlib_dirs)
+stdlib_dirs_any=$(HARECACHE)/dirs/dirs-any.o
+stdlib_deps_any+=$(stdlib_dirs_any)
+stdlib_dirs_linux=$(stdlib_dirs_any)
+stdlib_dirs_freebsd=$(stdlib_dirs_any)
# gen_lib encoding::base64 (any)
-stdlib_encoding_base64=$(HARECACHE)/encoding/base64/encoding_base64-any.o
-hare_stdlib_deps+=$(stdlib_encoding_base64)
+stdlib_encoding_base64_any=$(HARECACHE)/encoding/base64/encoding_base64-any.o
+stdlib_deps_any+=$(stdlib_encoding_base64_any)
+stdlib_encoding_base64_linux=$(stdlib_encoding_base64_any)
+stdlib_encoding_base64_freebsd=$(stdlib_encoding_base64_any)
# gen_lib encoding::hex (any)
-stdlib_encoding_hex=$(HARECACHE)/encoding/hex/encoding_hex-any.o
-hare_stdlib_deps+=$(stdlib_encoding_hex)
+stdlib_encoding_hex_any=$(HARECACHE)/encoding/hex/encoding_hex-any.o
+stdlib_deps_any+=$(stdlib_encoding_hex_any)
+stdlib_encoding_hex_linux=$(stdlib_encoding_hex_any)
+stdlib_encoding_hex_freebsd=$(stdlib_encoding_hex_any)
# gen_lib encoding::utf8 (any)
-stdlib_encoding_utf8=$(HARECACHE)/encoding/utf8/encoding_utf8-any.o
-hare_stdlib_deps+=$(stdlib_encoding_utf8)
+stdlib_encoding_utf8_any=$(HARECACHE)/encoding/utf8/encoding_utf8-any.o
+stdlib_deps_any+=$(stdlib_encoding_utf8_any)
+stdlib_encoding_utf8_linux=$(stdlib_encoding_utf8_any)
+stdlib_encoding_utf8_freebsd=$(stdlib_encoding_utf8_any)
# gen_lib endian (any)
-stdlib_endian=$(HARECACHE)/endian/endian-any.o
-hare_stdlib_deps+=$(stdlib_endian)
+stdlib_endian_any=$(HARECACHE)/endian/endian-any.o
+stdlib_deps_any+=$(stdlib_endian_any)
+stdlib_endian_linux=$(stdlib_endian_any)
+stdlib_endian_freebsd=$(stdlib_endian_any)
# gen_lib errors (any)
-stdlib_errors=$(HARECACHE)/errors/errors-any.o
-hare_stdlib_deps+=$(stdlib_errors)
+stdlib_errors_any=$(HARECACHE)/errors/errors-any.o
+stdlib_deps_any+=$(stdlib_errors_any)
+stdlib_errors_linux=$(stdlib_errors_any)
+stdlib_errors_freebsd=$(stdlib_errors_any)
# gen_lib fmt (any)
-stdlib_fmt=$(HARECACHE)/fmt/fmt-any.o
-hare_stdlib_deps+=$(stdlib_fmt)
+stdlib_fmt_any=$(HARECACHE)/fmt/fmt-any.o
+stdlib_deps_any+=$(stdlib_fmt_any)
+stdlib_fmt_linux=$(stdlib_fmt_any)
+stdlib_fmt_freebsd=$(stdlib_fmt_any)
# gen_lib fnmatch (any)
-stdlib_fnmatch=$(HARECACHE)/fnmatch/fnmatch-any.o
-hare_stdlib_deps+=$(stdlib_fnmatch)
+stdlib_fnmatch_any=$(HARECACHE)/fnmatch/fnmatch-any.o
+stdlib_deps_any+=$(stdlib_fnmatch_any)
+stdlib_fnmatch_linux=$(stdlib_fnmatch_any)
+stdlib_fnmatch_freebsd=$(stdlib_fnmatch_any)
# gen_lib format::elf (any)
-stdlib_format_elf=$(HARECACHE)/format/elf/format_elf-any.o
-hare_stdlib_deps+=$(stdlib_format_elf)
+stdlib_format_elf_any=$(HARECACHE)/format/elf/format_elf-any.o
+stdlib_deps_any+=$(stdlib_format_elf_any)
+stdlib_format_elf_linux=$(stdlib_format_elf_any)
+stdlib_format_elf_freebsd=$(stdlib_format_elf_any)
# gen_lib format::ini (any)
-stdlib_format_ini=$(HARECACHE)/format/ini/format_ini-any.o
-hare_stdlib_deps+=$(stdlib_format_ini)
+stdlib_format_ini_any=$(HARECACHE)/format/ini/format_ini-any.o
+stdlib_deps_any+=$(stdlib_format_ini_any)
+stdlib_format_ini_linux=$(stdlib_format_ini_any)
+stdlib_format_ini_freebsd=$(stdlib_format_ini_any)
# gen_lib format::xml (any)
-stdlib_format_xml=$(HARECACHE)/format/xml/format_xml-any.o
-hare_stdlib_deps+=$(stdlib_format_xml)
+stdlib_format_xml_any=$(HARECACHE)/format/xml/format_xml-any.o
+stdlib_deps_any+=$(stdlib_format_xml_any)
+stdlib_format_xml_linux=$(stdlib_format_xml_any)
+stdlib_format_xml_freebsd=$(stdlib_format_xml_any)
# gen_lib fs (any)
-stdlib_fs=$(HARECACHE)/fs/fs-any.o
-hare_stdlib_deps+=$(stdlib_fs)
+stdlib_fs_any=$(HARECACHE)/fs/fs-any.o
+stdlib_deps_any+=$(stdlib_fs_any)
+stdlib_fs_linux=$(stdlib_fs_any)
+stdlib_fs_freebsd=$(stdlib_fs_any)
# gen_lib fs::mem (any)
-stdlib_fs_mem=$(HARECACHE)/fs/mem/fs_mem-any.o
-hare_stdlib_deps+=$(stdlib_fs_mem)
+stdlib_fs_mem_any=$(HARECACHE)/fs/mem/fs_mem-any.o
+stdlib_deps_any+=$(stdlib_fs_mem_any)
+stdlib_fs_mem_linux=$(stdlib_fs_mem_any)
+stdlib_fs_mem_freebsd=$(stdlib_fs_mem_any)
# gen_lib getopt (any)
-stdlib_getopt=$(HARECACHE)/getopt/getopt-any.o
-hare_stdlib_deps+=$(stdlib_getopt)
+stdlib_getopt_any=$(HARECACHE)/getopt/getopt-any.o
+stdlib_deps_any+=$(stdlib_getopt_any)
+stdlib_getopt_linux=$(stdlib_getopt_any)
+stdlib_getopt_freebsd=$(stdlib_getopt_any)
# gen_lib hare::ast (any)
-stdlib_hare_ast=$(HARECACHE)/hare/ast/hare_ast-any.o
-hare_stdlib_deps+=$(stdlib_hare_ast)
+stdlib_hare_ast_any=$(HARECACHE)/hare/ast/hare_ast-any.o
+stdlib_deps_any+=$(stdlib_hare_ast_any)
+stdlib_hare_ast_linux=$(stdlib_hare_ast_any)
+stdlib_hare_ast_freebsd=$(stdlib_hare_ast_any)
# gen_lib hare::lex (any)
-stdlib_hare_lex=$(HARECACHE)/hare/lex/hare_lex-any.o
-hare_stdlib_deps+=$(stdlib_hare_lex)
+stdlib_hare_lex_any=$(HARECACHE)/hare/lex/hare_lex-any.o
+stdlib_deps_any+=$(stdlib_hare_lex_any)
+stdlib_hare_lex_linux=$(stdlib_hare_lex_any)
+stdlib_hare_lex_freebsd=$(stdlib_hare_lex_any)
# gen_lib hare::module (any)
-stdlib_hare_module=$(HARECACHE)/hare/module/hare_module-any.o
-hare_stdlib_deps+=$(stdlib_hare_module)
+stdlib_hare_module_any=$(HARECACHE)/hare/module/hare_module-any.o
+stdlib_deps_any+=$(stdlib_hare_module_any)
+stdlib_hare_module_linux=$(stdlib_hare_module_any)
+stdlib_hare_module_freebsd=$(stdlib_hare_module_any)
# gen_lib hare::parse (any)
-stdlib_hare_parse=$(HARECACHE)/hare/parse/hare_parse-any.o
-hare_stdlib_deps+=$(stdlib_hare_parse)
+stdlib_hare_parse_any=$(HARECACHE)/hare/parse/hare_parse-any.o
+stdlib_deps_any+=$(stdlib_hare_parse_any)
+stdlib_hare_parse_linux=$(stdlib_hare_parse_any)
+stdlib_hare_parse_freebsd=$(stdlib_hare_parse_any)
# gen_lib hare::types (any)
-stdlib_hare_types=$(HARECACHE)/hare/types/hare_types-any.o
-hare_stdlib_deps+=$(stdlib_hare_types)
+stdlib_hare_types_any=$(HARECACHE)/hare/types/hare_types-any.o
+stdlib_deps_any+=$(stdlib_hare_types_any)
+stdlib_hare_types_linux=$(stdlib_hare_types_any)
+stdlib_hare_types_freebsd=$(stdlib_hare_types_any)
# gen_lib hare::unit (any)
-stdlib_hare_unit=$(HARECACHE)/hare/unit/hare_unit-any.o
-hare_stdlib_deps+=$(stdlib_hare_unit)
+stdlib_hare_unit_any=$(HARECACHE)/hare/unit/hare_unit-any.o
+stdlib_deps_any+=$(stdlib_hare_unit_any)
+stdlib_hare_unit_linux=$(stdlib_hare_unit_any)
+stdlib_hare_unit_freebsd=$(stdlib_hare_unit_any)
# gen_lib hare::unparse (any)
-stdlib_hare_unparse=$(HARECACHE)/hare/unparse/hare_unparse-any.o
-hare_stdlib_deps+=$(stdlib_hare_unparse)
+stdlib_hare_unparse_any=$(HARECACHE)/hare/unparse/hare_unparse-any.o
+stdlib_deps_any+=$(stdlib_hare_unparse_any)
+stdlib_hare_unparse_linux=$(stdlib_hare_unparse_any)
+stdlib_hare_unparse_freebsd=$(stdlib_hare_unparse_any)
# gen_lib hash (any)
-stdlib_hash=$(HARECACHE)/hash/hash-any.o
-hare_stdlib_deps+=$(stdlib_hash)
+stdlib_hash_any=$(HARECACHE)/hash/hash-any.o
+stdlib_deps_any+=$(stdlib_hash_any)
+stdlib_hash_linux=$(stdlib_hash_any)
+stdlib_hash_freebsd=$(stdlib_hash_any)
# gen_lib hash::adler32 (any)
-stdlib_hash_adler32=$(HARECACHE)/hash/adler32/hash_adler32-any.o
-hare_stdlib_deps+=$(stdlib_hash_adler32)
+stdlib_hash_adler32_any=$(HARECACHE)/hash/adler32/hash_adler32-any.o
+stdlib_deps_any+=$(stdlib_hash_adler32_any)
+stdlib_hash_adler32_linux=$(stdlib_hash_adler32_any)
+stdlib_hash_adler32_freebsd=$(stdlib_hash_adler32_any)
# gen_lib hash::crc16 (any)
-stdlib_hash_crc16=$(HARECACHE)/hash/crc16/hash_crc16-any.o
-hare_stdlib_deps+=$(stdlib_hash_crc16)
+stdlib_hash_crc16_any=$(HARECACHE)/hash/crc16/hash_crc16-any.o
+stdlib_deps_any+=$(stdlib_hash_crc16_any)
+stdlib_hash_crc16_linux=$(stdlib_hash_crc16_any)
+stdlib_hash_crc16_freebsd=$(stdlib_hash_crc16_any)
# gen_lib hash::crc32 (any)
-stdlib_hash_crc32=$(HARECACHE)/hash/crc32/hash_crc32-any.o
-hare_stdlib_deps+=$(stdlib_hash_crc32)
+stdlib_hash_crc32_any=$(HARECACHE)/hash/crc32/hash_crc32-any.o
+stdlib_deps_any+=$(stdlib_hash_crc32_any)
+stdlib_hash_crc32_linux=$(stdlib_hash_crc32_any)
+stdlib_hash_crc32_freebsd=$(stdlib_hash_crc32_any)
# gen_lib hash::crc64 (any)
-stdlib_hash_crc64=$(HARECACHE)/hash/crc64/hash_crc64-any.o
-hare_stdlib_deps+=$(stdlib_hash_crc64)
+stdlib_hash_crc64_any=$(HARECACHE)/hash/crc64/hash_crc64-any.o
+stdlib_deps_any+=$(stdlib_hash_crc64_any)
+stdlib_hash_crc64_linux=$(stdlib_hash_crc64_any)
+stdlib_hash_crc64_freebsd=$(stdlib_hash_crc64_any)
# gen_lib hash::fnv (any)
-stdlib_hash_fnv=$(HARECACHE)/hash/fnv/hash_fnv-any.o
-hare_stdlib_deps+=$(stdlib_hash_fnv)
+stdlib_hash_fnv_any=$(HARECACHE)/hash/fnv/hash_fnv-any.o
+stdlib_deps_any+=$(stdlib_hash_fnv_any)
+stdlib_hash_fnv_linux=$(stdlib_hash_fnv_any)
+stdlib_hash_fnv_freebsd=$(stdlib_hash_fnv_any)
# gen_lib io (linux)
-stdlib_io=$(HARECACHE)/io/io-linux.o
-hare_stdlib_deps+=$(stdlib_io)
+stdlib_io_linux=$(HARECACHE)/io/io-linux.o
+stdlib_deps_linux+=$(stdlib_io_linux)
+
+# gen_lib io (freebsd)
+stdlib_io_freebsd=$(HARECACHE)/io/io-freebsd.o
+stdlib_deps_freebsd+=$(stdlib_io_freebsd)
# gen_lib iobus::io_uring (linux)
-stdlib_iobus_io_uring=$(HARECACHE)/iobus/io_uring/iobus_io_uring-linux.o
-hare_stdlib_deps+=$(stdlib_iobus_io_uring)
+stdlib_iobus_io_uring_linux=$(HARECACHE)/iobus/io_uring/iobus_io_uring-linux.o
+stdlib_deps_linux+=$(stdlib_iobus_io_uring_linux)
# gen_lib linux (linux)
-stdlib_linux=$(HARECACHE)/linux/linux-linux.o
-hare_stdlib_deps+=$(stdlib_linux)
+stdlib_linux_linux=$(HARECACHE)/linux/linux-linux.o
+stdlib_deps_linux+=$(stdlib_linux_linux)
# gen_lib linux::signalfd (linux)
-stdlib_linux_signalfd=$(HARECACHE)/linux/signalfd/linux_signalfd-linux.o
-hare_stdlib_deps+=$(stdlib_linux_signalfd)
+stdlib_linux_signalfd_linux=$(HARECACHE)/linux/signalfd/linux_signalfd-linux.o
+stdlib_deps_linux+=$(stdlib_linux_signalfd_linux)
# gen_lib linux::io_uring (linux)
-stdlib_linux_io_uring=$(HARECACHE)/linux/io_uring/linux_io_uring-linux.o
-hare_stdlib_deps+=$(stdlib_linux_io_uring)
+stdlib_linux_io_uring_linux=$(HARECACHE)/linux/io_uring/linux_io_uring-linux.o
+stdlib_deps_linux+=$(stdlib_linux_io_uring_linux)
# gen_lib linux::vdso (linux)
-stdlib_linux_vdso=$(HARECACHE)/linux/vdso/linux_vdso-linux.o
-hare_stdlib_deps+=$(stdlib_linux_vdso)
+stdlib_linux_vdso_linux=$(HARECACHE)/linux/vdso/linux_vdso-linux.o
+stdlib_deps_linux+=$(stdlib_linux_vdso_linux)
# gen_lib math (any)
-stdlib_math=$(HARECACHE)/math/math-any.o
-hare_stdlib_deps+=$(stdlib_math)
+stdlib_math_any=$(HARECACHE)/math/math-any.o
+stdlib_deps_any+=$(stdlib_math_any)
+stdlib_math_linux=$(stdlib_math_any)
+stdlib_math_freebsd=$(stdlib_math_any)
# gen_lib net (linux)
-stdlib_net=$(HARECACHE)/net/net-linux.o
-hare_stdlib_deps+=$(stdlib_net)
+stdlib_net_linux=$(HARECACHE)/net/net-linux.o
+stdlib_deps_linux+=$(stdlib_net_linux)
+
+# gen_lib net (freebsd)
+stdlib_net_freebsd=$(HARECACHE)/net/net-freebsd.o
+stdlib_deps_freebsd+=$(stdlib_net_freebsd)
# gen_lib net::dial (any)
-stdlib_net_dial=$(HARECACHE)/net/dial/net_dial-any.o
-hare_stdlib_deps+=$(stdlib_net_dial)
+stdlib_net_dial_any=$(HARECACHE)/net/dial/net_dial-any.o
+stdlib_deps_any+=$(stdlib_net_dial_any)
+stdlib_net_dial_linux=$(stdlib_net_dial_any)
+stdlib_net_dial_freebsd=$(stdlib_net_dial_any)
# gen_lib net::dns (any)
-stdlib_net_dns=$(HARECACHE)/net/dns/net_dns-any.o
-hare_stdlib_deps+=$(stdlib_net_dns)
+stdlib_net_dns_any=$(HARECACHE)/net/dns/net_dns-any.o
+stdlib_deps_any+=$(stdlib_net_dns_any)
+stdlib_net_dns_linux=$(stdlib_net_dns_any)
+stdlib_net_dns_freebsd=$(stdlib_net_dns_any)
# gen_lib net::ip (linux)
-stdlib_net_ip=$(HARECACHE)/net/ip/net_ip-linux.o
-hare_stdlib_deps+=$(stdlib_net_ip)
+stdlib_net_ip_linux=$(HARECACHE)/net/ip/net_ip-linux.o
+stdlib_deps_linux+=$(stdlib_net_ip_linux)
+
+# gen_lib net::ip (freebsd)
+stdlib_net_ip_freebsd=$(HARECACHE)/net/ip/net_ip-freebsd.o
+stdlib_deps_freebsd+=$(stdlib_net_ip_freebsd)
# gen_lib net::tcp (linux)
-stdlib_net_tcp=$(HARECACHE)/net/tcp/net_tcp-linux.o
-hare_stdlib_deps+=$(stdlib_net_tcp)
+stdlib_net_tcp_linux=$(HARECACHE)/net/tcp/net_tcp-linux.o
+stdlib_deps_linux+=$(stdlib_net_tcp_linux)
+
+# gen_lib net::tcp (freebsd)
+stdlib_net_tcp_freebsd=$(HARECACHE)/net/tcp/net_tcp-freebsd.o
+stdlib_deps_freebsd+=$(stdlib_net_tcp_freebsd)
# gen_lib net::udp (linux)
-stdlib_net_udp=$(HARECACHE)/net/udp/net_udp-linux.o
-hare_stdlib_deps+=$(stdlib_net_udp)
+stdlib_net_udp_linux=$(HARECACHE)/net/udp/net_udp-linux.o
+stdlib_deps_linux+=$(stdlib_net_udp_linux)
+
+# gen_lib net::udp (freebsd)
+stdlib_net_udp_freebsd=$(HARECACHE)/net/udp/net_udp-freebsd.o
+stdlib_deps_freebsd+=$(stdlib_net_udp_freebsd)
# gen_lib net::unix (linux)
-stdlib_net_unix=$(HARECACHE)/net/unix/net_unix-linux.o
-hare_stdlib_deps+=$(stdlib_net_unix)
+stdlib_net_unix_linux=$(HARECACHE)/net/unix/net_unix-linux.o
+stdlib_deps_linux+=$(stdlib_net_unix_linux)
+
+# gen_lib net::unix (freebsd)
+stdlib_net_unix_freebsd=$(HARECACHE)/net/unix/net_unix-freebsd.o
+stdlib_deps_freebsd+=$(stdlib_net_unix_freebsd)
# gen_lib math::random (any)
-stdlib_math_random=$(HARECACHE)/math/random/math_random-any.o
-hare_stdlib_deps+=$(stdlib_math_random)
+stdlib_math_random_any=$(HARECACHE)/math/random/math_random-any.o
+stdlib_deps_any+=$(stdlib_math_random_any)
+stdlib_math_random_linux=$(stdlib_math_random_any)
+stdlib_math_random_freebsd=$(stdlib_math_random_any)
# gen_lib os (linux)
-stdlib_os=$(HARECACHE)/os/os-linux.o
-hare_stdlib_deps+=$(stdlib_os)
+stdlib_os_linux=$(HARECACHE)/os/os-linux.o
+stdlib_deps_linux+=$(stdlib_os_linux)
+
+# gen_lib os (freebsd)
+stdlib_os_freebsd=$(HARECACHE)/os/os-freebsd.o
+stdlib_deps_freebsd+=$(stdlib_os_freebsd)
# gen_lib os::exec (linux)
-stdlib_os_exec=$(HARECACHE)/os/exec/os_exec-linux.o
-hare_stdlib_deps+=$(stdlib_os_exec)
+stdlib_os_exec_linux=$(HARECACHE)/os/exec/os_exec-linux.o
+stdlib_deps_linux+=$(stdlib_os_exec_linux)
+
+# gen_lib os::exec (freebsd)
+stdlib_os_exec_freebsd=$(HARECACHE)/os/exec/os_exec-freebsd.o
+stdlib_deps_freebsd+=$(stdlib_os_exec_freebsd)
# gen_lib path (any)
-stdlib_path=$(HARECACHE)/path/path-any.o
-hare_stdlib_deps+=$(stdlib_path)
+stdlib_path_any=$(HARECACHE)/path/path-any.o
+stdlib_deps_any+=$(stdlib_path_any)
+stdlib_path_linux=$(stdlib_path_any)
+stdlib_path_freebsd=$(stdlib_path_any)
# gen_lib slice (any)
-stdlib_slice=$(HARECACHE)/slice/slice-any.o
-hare_stdlib_deps+=$(stdlib_slice)
+stdlib_slice_any=$(HARECACHE)/slice/slice-any.o
+stdlib_deps_any+=$(stdlib_slice_any)
+stdlib_slice_linux=$(stdlib_slice_any)
+stdlib_slice_freebsd=$(stdlib_slice_any)
# gen_lib sort (any)
-stdlib_sort=$(HARECACHE)/sort/sort-any.o
-hare_stdlib_deps+=$(stdlib_sort)
+stdlib_sort_any=$(HARECACHE)/sort/sort-any.o
+stdlib_deps_any+=$(stdlib_sort_any)
+stdlib_sort_linux=$(stdlib_sort_any)
+stdlib_sort_freebsd=$(stdlib_sort_any)
# gen_lib strconv (any)
-stdlib_strconv=$(HARECACHE)/strconv/strconv-any.o
-hare_stdlib_deps+=$(stdlib_strconv)
+stdlib_strconv_any=$(HARECACHE)/strconv/strconv-any.o
+stdlib_deps_any+=$(stdlib_strconv_any)
+stdlib_strconv_linux=$(stdlib_strconv_any)
+stdlib_strconv_freebsd=$(stdlib_strconv_any)
# gen_lib strings (any)
-stdlib_strings=$(HARECACHE)/strings/strings-any.o
-hare_stdlib_deps+=$(stdlib_strings)
+stdlib_strings_any=$(HARECACHE)/strings/strings-any.o
+stdlib_deps_any+=$(stdlib_strings_any)
+stdlib_strings_linux=$(stdlib_strings_any)
+stdlib_strings_freebsd=$(stdlib_strings_any)
# gen_lib strio (any)
-stdlib_strio=$(HARECACHE)/strio/strio-any.o
-hare_stdlib_deps+=$(stdlib_strio)
+stdlib_strio_any=$(HARECACHE)/strio/strio-any.o
+stdlib_deps_any+=$(stdlib_strio_any)
+stdlib_strio_linux=$(stdlib_strio_any)
+stdlib_strio_freebsd=$(stdlib_strio_any)
# gen_lib temp (linux)
-stdlib_temp=$(HARECACHE)/temp/temp-linux.o
-hare_stdlib_deps+=$(stdlib_temp)
+stdlib_temp_linux=$(HARECACHE)/temp/temp-linux.o
+stdlib_deps_linux+=$(stdlib_temp_linux)
+
+# gen_lib temp (freebsd)
+stdlib_temp_freebsd=$(HARECACHE)/temp/temp-freebsd.o
+stdlib_deps_freebsd+=$(stdlib_temp_freebsd)
# gen_lib time (linux)
-stdlib_time=$(HARECACHE)/time/time-linux.o
-hare_stdlib_deps+=$(stdlib_time)
+stdlib_time_linux=$(HARECACHE)/time/time-linux.o
+stdlib_deps_linux+=$(stdlib_time_linux)
+
+# gen_lib time (freebsd)
+stdlib_time_freebsd=$(HARECACHE)/time/time-freebsd.o
+stdlib_deps_freebsd+=$(stdlib_time_freebsd)
# gen_lib types (any)
-stdlib_types=$(HARECACHE)/types/types-any.o
-hare_stdlib_deps+=$(stdlib_types)
+stdlib_types_any=$(HARECACHE)/types/types-any.o
+stdlib_deps_any+=$(stdlib_types_any)
+stdlib_types_linux=$(stdlib_types_any)
+stdlib_types_freebsd=$(stdlib_types_any)
# gen_lib unix (linux)
-stdlib_unix=$(HARECACHE)/unix/unix-linux.o
-hare_stdlib_deps+=$(stdlib_unix)
+stdlib_unix_linux=$(HARECACHE)/unix/unix-linux.o
+stdlib_deps_linux+=$(stdlib_unix_linux)
+
+# gen_lib unix (freebsd)
+stdlib_unix_freebsd=$(HARECACHE)/unix/unix-freebsd.o
+stdlib_deps_freebsd+=$(stdlib_unix_freebsd)
# gen_lib unix::hosts (any)
-stdlib_unix_hosts=$(HARECACHE)/unix/hosts/unix_hosts-any.o
-hare_stdlib_deps+=$(stdlib_unix_hosts)
+stdlib_unix_hosts_any=$(HARECACHE)/unix/hosts/unix_hosts-any.o
+stdlib_deps_any+=$(stdlib_unix_hosts_any)
+stdlib_unix_hosts_linux=$(stdlib_unix_hosts_any)
+stdlib_unix_hosts_freebsd=$(stdlib_unix_hosts_any)
# gen_lib unix::passwd (any)
-stdlib_unix_passwd=$(HARECACHE)/unix/passwd/unix_passwd-any.o
-hare_stdlib_deps+=$(stdlib_unix_passwd)
+stdlib_unix_passwd_any=$(HARECACHE)/unix/passwd/unix_passwd-any.o
+stdlib_deps_any+=$(stdlib_unix_passwd_any)
+stdlib_unix_passwd_linux=$(stdlib_unix_passwd_any)
+stdlib_unix_passwd_freebsd=$(stdlib_unix_passwd_any)
# gen_lib unix::poll (linux)
-stdlib_unix_poll=$(HARECACHE)/unix/poll/unix_poll-linux.o
-hare_stdlib_deps+=$(stdlib_unix_poll)
+stdlib_unix_poll_linux=$(HARECACHE)/unix/poll/unix_poll-linux.o
+stdlib_deps_linux+=$(stdlib_unix_poll_linux)
+
+# gen_lib unix::poll (freebsd)
+stdlib_unix_poll_freebsd=$(HARECACHE)/unix/poll/unix_poll-freebsd.o
+stdlib_deps_freebsd+=$(stdlib_unix_poll_freebsd)
# gen_lib unix::resolvconf (any)
-stdlib_unix_resolvconf=$(HARECACHE)/unix/resolvconf/unix_resolvconf-any.o
-hare_stdlib_deps+=$(stdlib_unix_resolvconf)
+stdlib_unix_resolvconf_any=$(HARECACHE)/unix/resolvconf/unix_resolvconf-any.o
+stdlib_deps_any+=$(stdlib_unix_resolvconf_any)
+stdlib_unix_resolvconf_linux=$(stdlib_unix_resolvconf_any)
+stdlib_unix_resolvconf_freebsd=$(stdlib_unix_resolvconf_any)
# gen_lib unix::tty (linux)
-stdlib_unix_tty=$(HARECACHE)/unix/tty/unix_tty-linux.o
-hare_stdlib_deps+=$(stdlib_unix_tty)
+stdlib_unix_tty_linux=$(HARECACHE)/unix/tty/unix_tty-linux.o
+stdlib_deps_linux+=$(stdlib_unix_tty_linux)
+
+# gen_lib unix::tty (freebsd)
+stdlib_unix_tty_freebsd=$(HARECACHE)/unix/tty/unix_tty-freebsd.o
+stdlib_deps_freebsd+=$(stdlib_unix_tty_freebsd)
# gen_lib uuid (any)
-stdlib_uuid=$(HARECACHE)/uuid/uuid-any.o
-hare_stdlib_deps+=$(stdlib_uuid)
+stdlib_uuid_any=$(HARECACHE)/uuid/uuid-any.o
+stdlib_deps_any+=$(stdlib_uuid_any)
+stdlib_uuid_linux=$(stdlib_uuid_any)
+stdlib_uuid_freebsd=$(stdlib_uuid_any)
# ascii (+any)
stdlib_ascii_any_srcs= \
$(STDLIB)/ascii/ctype.ha \
$(STDLIB)/ascii/strcmp.ha
-$(HARECACHE)/ascii/ascii-any.ssa: $(stdlib_ascii_any_srcs) $(stdlib_rt) $(stdlib_strings)
+$(HARECACHE)/ascii/ascii-any.ssa: $(stdlib_ascii_any_srcs) $(stdlib_rt) $(stdlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/ascii
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nascii \
@@ -385,7 +585,7 @@ stdlib_bufio_any_srcs= \
$(STDLIB)/bufio/memstream.ha \
$(STDLIB)/bufio/scanner.ha
-$(HARECACHE)/bufio/bufio-any.ssa: $(stdlib_bufio_any_srcs) $(stdlib_rt) $(stdlib_io) $(stdlib_bytes) $(stdlib_strings) $(stdlib_encoding_utf8) $(stdlib_errors) $(stdlib_types)
+$(HARECACHE)/bufio/bufio-any.ssa: $(stdlib_bufio_any_srcs) $(stdlib_rt) $(stdlib_io_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_encoding_utf8_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_types_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/bufio
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nbufio \
@@ -401,7 +601,7 @@ stdlib_bytes_any_srcs= \
$(STDLIB)/bytes/tokenize.ha \
$(STDLIB)/bytes/two_way.ha
-$(HARECACHE)/bytes/bytes-any.ssa: $(stdlib_bytes_any_srcs) $(stdlib_rt) $(stdlib_types)
+$(HARECACHE)/bytes/bytes-any.ssa: $(stdlib_bytes_any_srcs) $(stdlib_rt) $(stdlib_types_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/bytes
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nbytes \
@@ -411,7 +611,7 @@ $(HARECACHE)/bytes/bytes-any.ssa: $(stdlib_bytes_any_srcs) $(stdlib_rt) $(stdlib
stdlib_compress_flate_any_srcs= \
$(STDLIB)/compress/flate/inflate.ha
-$(HARECACHE)/compress/flate/compress_flate-any.ssa: $(stdlib_compress_flate_any_srcs) $(stdlib_rt) $(stdlib_bufio) $(stdlib_bytes) $(stdlib_endian) $(stdlib_errors) $(stdlib_io) $(stdlib_fmt)
+$(HARECACHE)/compress/flate/compress_flate-any.ssa: $(stdlib_compress_flate_any_srcs) $(stdlib_rt) $(stdlib_bufio_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) $(stdlib_endian_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/compress/flate
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncompress::flate \
@@ -421,7 +621,7 @@ $(HARECACHE)/compress/flate/compress_flate-any.ssa: $(stdlib_compress_flate_any_
stdlib_compress_zlib_any_srcs= \
$(STDLIB)/compress/zlib/reader.ha
-$(HARECACHE)/compress/zlib/compress_zlib-any.ssa: $(stdlib_compress_zlib_any_srcs) $(stdlib_rt) $(stdlib_bufio) $(stdlib_bytes) $(stdlib_compress_flate) $(stdlib_endian) $(stdlib_errors) $(stdlib_hash) $(stdlib_hash_adler32) $(stdlib_io) $(stdlib_fmt)
+$(HARECACHE)/compress/zlib/compress_zlib-any.ssa: $(stdlib_compress_zlib_any_srcs) $(stdlib_rt) $(stdlib_bufio_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) $(stdlib_compress_flate_$(PLATFORM)) $(stdlib_endian_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_hash_adler32_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/compress/zlib
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncompress::zlib \
@@ -431,7 +631,7 @@ $(HARECACHE)/compress/zlib/compress_zlib-any.ssa: $(stdlib_compress_zlib_any_src
stdlib_crypto_blake2b_any_srcs= \
$(STDLIB)/crypto/blake2b/blake2b.ha
-$(HARECACHE)/crypto/blake2b/crypto_blake2b-any.ssa: $(stdlib_crypto_blake2b_any_srcs) $(stdlib_rt) $(stdlib_encoding_hex) $(stdlib_fmt) $(stdlib_hash) $(stdlib_io) $(stdlib_strings) $(stdlib_strio) $(stdlib_crypto_math) $(stdlib_endian)
+$(HARECACHE)/crypto/blake2b/crypto_blake2b-any.ssa: $(stdlib_crypto_blake2b_any_srcs) $(stdlib_rt) $(stdlib_encoding_hex_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_strio_$(PLATFORM)) $(stdlib_crypto_math_$(PLATFORM)) $(stdlib_endian_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/crypto/blake2b
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncrypto::blake2b \
@@ -452,17 +652,28 @@ stdlib_crypto_random_linux_srcs= \
$(STDLIB)/crypto/random/+linux.ha \
$(STDLIB)/crypto/random/random.ha
-$(HARECACHE)/crypto/random/crypto_random-linux.ssa: $(stdlib_crypto_random_linux_srcs) $(stdlib_rt) $(stdlib_rt) $(stdlib_io) $(stdlib_errors)
+$(HARECACHE)/crypto/random/crypto_random-linux.ssa: $(stdlib_crypto_random_linux_srcs) $(stdlib_rt) $(stdlib_rt_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_errors_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/crypto/random
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncrypto::random \
-t$(HARECACHE)/crypto/random/crypto_random.td $(stdlib_crypto_random_linux_srcs)
+# crypto::random (+freebsd)
+stdlib_crypto_random_freebsd_srcs= \
+ $(STDLIB)/crypto/random/+freebsd.ha \
+ $(STDLIB)/crypto/random/random.ha
+
+$(HARECACHE)/crypto/random/crypto_random-freebsd.ssa: $(stdlib_crypto_random_freebsd_srcs) $(stdlib_rt) $(stdlib_rt_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_errors_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/crypto/random
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncrypto::random \
+ -t$(HARECACHE)/crypto/random/crypto_random.td $(stdlib_crypto_random_freebsd_srcs)
+
# crypto::md5 (+any)
stdlib_crypto_md5_any_srcs= \
$(STDLIB)/crypto/md5/md5.ha
-$(HARECACHE)/crypto/md5/crypto_md5-any.ssa: $(stdlib_crypto_md5_any_srcs) $(stdlib_rt) $(stdlib_hash) $(stdlib_io) $(stdlib_endian)
+$(HARECACHE)/crypto/md5/crypto_md5-any.ssa: $(stdlib_crypto_md5_any_srcs) $(stdlib_rt) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_endian_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/crypto/md5
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncrypto::md5 \
@@ -472,7 +683,7 @@ $(HARECACHE)/crypto/md5/crypto_md5-any.ssa: $(stdlib_crypto_md5_any_srcs) $(stdl
stdlib_crypto_sha1_any_srcs= \
$(STDLIB)/crypto/sha1/sha1.ha
-$(HARECACHE)/crypto/sha1/crypto_sha1-any.ssa: $(stdlib_crypto_sha1_any_srcs) $(stdlib_rt) $(stdlib_hash) $(stdlib_io) $(stdlib_endian)
+$(HARECACHE)/crypto/sha1/crypto_sha1-any.ssa: $(stdlib_crypto_sha1_any_srcs) $(stdlib_rt) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_endian_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/crypto/sha1
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncrypto::sha1 \
@@ -482,7 +693,7 @@ $(HARECACHE)/crypto/sha1/crypto_sha1-any.ssa: $(stdlib_crypto_sha1_any_srcs) $(s
stdlib_crypto_sha256_any_srcs= \
$(STDLIB)/crypto/sha256/sha256.ha
-$(HARECACHE)/crypto/sha256/crypto_sha256-any.ssa: $(stdlib_crypto_sha256_any_srcs) $(stdlib_rt) $(stdlib_hash) $(stdlib_io) $(stdlib_endian)
+$(HARECACHE)/crypto/sha256/crypto_sha256-any.ssa: $(stdlib_crypto_sha256_any_srcs) $(stdlib_rt) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_endian_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/crypto/sha256
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncrypto::sha256 \
@@ -492,7 +703,7 @@ $(HARECACHE)/crypto/sha256/crypto_sha256-any.ssa: $(stdlib_crypto_sha256_any_src
stdlib_crypto_sha512_any_srcs= \
$(STDLIB)/crypto/sha512/sha512.ha
-$(HARECACHE)/crypto/sha512/crypto_sha512-any.ssa: $(stdlib_crypto_sha512_any_srcs) $(stdlib_rt) $(stdlib_hash) $(stdlib_io) $(stdlib_endian)
+$(HARECACHE)/crypto/sha512/crypto_sha512-any.ssa: $(stdlib_crypto_sha512_any_srcs) $(stdlib_rt) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_endian_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/crypto/sha512
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncrypto::sha512 \
@@ -502,7 +713,7 @@ $(HARECACHE)/crypto/sha512/crypto_sha512-any.ssa: $(stdlib_crypto_sha512_any_src
stdlib_dirs_any_srcs= \
$(STDLIB)/dirs/xdg.ha
-$(HARECACHE)/dirs/dirs-any.ssa: $(stdlib_dirs_any_srcs) $(stdlib_rt) $(stdlib_fs) $(stdlib_os) $(stdlib_path)
+$(HARECACHE)/dirs/dirs-any.ssa: $(stdlib_dirs_any_srcs) $(stdlib_rt) $(stdlib_fs_$(PLATFORM)) $(stdlib_os_$(PLATFORM)) $(stdlib_path_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/dirs
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ndirs \
@@ -512,7 +723,7 @@ $(HARECACHE)/dirs/dirs-any.ssa: $(stdlib_dirs_any_srcs) $(stdlib_rt) $(stdlib_fs
stdlib_encoding_base64_any_srcs= \
$(STDLIB)/encoding/base64/base64.ha
-$(HARECACHE)/encoding/base64/encoding_base64-any.ssa: $(stdlib_encoding_base64_any_srcs) $(stdlib_rt) $(stdlib_bufio) $(stdlib_bytes) $(stdlib_io) $(stdlib_strio) $(stdlib_strings)
+$(HARECACHE)/encoding/base64/encoding_base64-any.ssa: $(stdlib_encoding_base64_any_srcs) $(stdlib_rt) $(stdlib_bufio_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_strio_$(PLATFORM)) $(stdlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/encoding/base64
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nencoding::base64 \
@@ -522,7 +733,7 @@ $(HARECACHE)/encoding/base64/encoding_base64-any.ssa: $(stdlib_encoding_base64_a
stdlib_encoding_hex_any_srcs= \
$(STDLIB)/encoding/hex/hex.ha
-$(HARECACHE)/encoding/hex/encoding_hex-any.ssa: $(stdlib_encoding_hex_any_srcs) $(stdlib_rt) $(stdlib_ascii) $(stdlib_bytes) $(stdlib_fmt) $(stdlib_io) $(stdlib_strconv) $(stdlib_strio) $(stdlib_strings)
+$(HARECACHE)/encoding/hex/encoding_hex-any.ssa: $(stdlib_encoding_hex_any_srcs) $(stdlib_rt) $(stdlib_ascii_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_strconv_$(PLATFORM)) $(stdlib_strio_$(PLATFORM)) $(stdlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/encoding/hex
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nencoding::hex \
@@ -534,7 +745,7 @@ stdlib_encoding_utf8_any_srcs= \
$(STDLIB)/encoding/utf8/encode.ha \
$(STDLIB)/encoding/utf8/rune.ha
-$(HARECACHE)/encoding/utf8/encoding_utf8-any.ssa: $(stdlib_encoding_utf8_any_srcs) $(stdlib_rt) $(stdlib_types)
+$(HARECACHE)/encoding/utf8/encoding_utf8-any.ssa: $(stdlib_encoding_utf8_any_srcs) $(stdlib_rt) $(stdlib_types_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/encoding/utf8
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nencoding::utf8 \
@@ -571,7 +782,7 @@ $(HARECACHE)/errors/errors-any.ssa: $(stdlib_errors_any_srcs) $(stdlib_rt)
stdlib_fmt_any_srcs= \
$(STDLIB)/fmt/fmt.ha
-$(HARECACHE)/fmt/fmt-any.ssa: $(stdlib_fmt_any_srcs) $(stdlib_rt) $(stdlib_bufio) $(stdlib_io) $(stdlib_os) $(stdlib_strconv) $(stdlib_strings) $(stdlib_types)
+$(HARECACHE)/fmt/fmt-any.ssa: $(stdlib_fmt_any_srcs) $(stdlib_rt) $(stdlib_bufio_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_os_$(PLATFORM)) $(stdlib_strconv_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_types_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/fmt
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nfmt \
@@ -581,7 +792,7 @@ $(HARECACHE)/fmt/fmt-any.ssa: $(stdlib_fmt_any_srcs) $(stdlib_rt) $(stdlib_bufio
stdlib_fnmatch_any_srcs= \
$(STDLIB)/fnmatch/fnmatch.ha
-$(HARECACHE)/fnmatch/fnmatch-any.ssa: $(stdlib_fnmatch_any_srcs) $(stdlib_rt) $(stdlib_strings) $(stdlib_bytes) $(stdlib_sort) $(stdlib_ascii) $(stdlib_io) $(stdlib_fmt)
+$(HARECACHE)/fnmatch/fnmatch-any.ssa: $(stdlib_fnmatch_any_srcs) $(stdlib_rt) $(stdlib_strings_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) $(stdlib_sort_$(PLATFORM)) $(stdlib_ascii_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/fnmatch
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nfnmatch \
@@ -604,7 +815,7 @@ stdlib_format_ini_any_srcs= \
$(STDLIB)/format/ini/scan.ha \
$(STDLIB)/format/ini/types.ha
-$(HARECACHE)/format/ini/format_ini-any.ssa: $(stdlib_format_ini_any_srcs) $(stdlib_rt) $(stdlib_bufio) $(stdlib_encoding_utf8) $(stdlib_fmt) $(stdlib_io) $(stdlib_strings)
+$(HARECACHE)/format/ini/format_ini-any.ssa: $(stdlib_format_ini_any_srcs) $(stdlib_rt) $(stdlib_bufio_$(PLATFORM)) $(stdlib_encoding_utf8_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/format/ini
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nformat::ini \
@@ -616,7 +827,7 @@ stdlib_format_xml_any_srcs= \
$(STDLIB)/format/xml/parser.ha \
$(STDLIB)/format/xml/chars.ha
-$(HARECACHE)/format/xml/format_xml-any.ssa: $(stdlib_format_xml_any_srcs) $(stdlib_rt) $(stdlib_io) $(stdlib_bufio) $(stdlib_strings) $(stdlib_ascii) $(stdlib_strio) $(stdlib_os)
+$(HARECACHE)/format/xml/format_xml-any.ssa: $(stdlib_format_xml_any_srcs) $(stdlib_rt) $(stdlib_io_$(PLATFORM)) $(stdlib_bufio_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_ascii_$(PLATFORM)) $(stdlib_strio_$(PLATFORM)) $(stdlib_os_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/format/xml
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nformat::xml \
@@ -628,7 +839,7 @@ stdlib_fs_any_srcs= \
$(STDLIB)/fs/fs.ha \
$(STDLIB)/fs/util.ha
-$(HARECACHE)/fs/fs-any.ssa: $(stdlib_fs_any_srcs) $(stdlib_rt) $(stdlib_io) $(stdlib_strings) $(stdlib_path) $(stdlib_time) $(stdlib_errors)
+$(HARECACHE)/fs/fs-any.ssa: $(stdlib_fs_any_srcs) $(stdlib_rt) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_path_$(PLATFORM)) $(stdlib_time_$(PLATFORM)) $(stdlib_errors_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/fs
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nfs \
@@ -640,7 +851,7 @@ stdlib_fs_mem_any_srcs= \
$(STDLIB)/fs/mem/stream.ha \
$(STDLIB)/fs/mem/util.ha
-$(HARECACHE)/fs/mem/fs_mem-any.ssa: $(stdlib_fs_mem_any_srcs) $(stdlib_rt) $(stdlib_bufio) $(stdlib_errors) $(stdlib_fs) $(stdlib_hash) $(stdlib_hash_fnv) $(stdlib_io) $(stdlib_path) $(stdlib_strconv) $(stdlib_strings) $(stdlib_types)
+$(HARECACHE)/fs/mem/fs_mem-any.ssa: $(stdlib_fs_mem_any_srcs) $(stdlib_rt) $(stdlib_bufio_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_fs_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_hash_fnv_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_path_$(PLATFORM)) $(stdlib_strconv_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_types_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/fs/mem
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nfs::mem \
@@ -650,7 +861,7 @@ $(HARECACHE)/fs/mem/fs_mem-any.ssa: $(stdlib_fs_mem_any_srcs) $(stdlib_rt) $(std
stdlib_getopt_any_srcs= \
$(STDLIB)/getopt/getopts.ha
-$(HARECACHE)/getopt/getopt-any.ssa: $(stdlib_getopt_any_srcs) $(stdlib_rt) $(stdlib_encoding_utf8) $(stdlib_fmt) $(stdlib_io) $(stdlib_os) $(stdlib_strings)
+$(HARECACHE)/getopt/getopt-any.ssa: $(stdlib_getopt_any_srcs) $(stdlib_rt) $(stdlib_encoding_utf8_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_os_$(PLATFORM)) $(stdlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/getopt
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ngetopt \
@@ -665,7 +876,7 @@ stdlib_hare_ast_any_srcs= \
$(STDLIB)/hare/ast/type.ha \
$(STDLIB)/hare/ast/unit.ha
-$(HARECACHE)/hare/ast/hare_ast-any.ssa: $(stdlib_hare_ast_any_srcs) $(stdlib_rt) $(stdlib_hare_lex) $(stdlib_strings)
+$(HARECACHE)/hare/ast/hare_ast-any.ssa: $(stdlib_hare_ast_any_srcs) $(stdlib_rt) $(stdlib_hare_lex_$(PLATFORM)) $(stdlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/hare/ast
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhare::ast \
@@ -676,7 +887,7 @@ stdlib_hare_lex_any_srcs= \
$(STDLIB)/hare/lex/token.ha \
$(STDLIB)/hare/lex/lex.ha
-$(HARECACHE)/hare/lex/hare_lex-any.ssa: $(stdlib_hare_lex_any_srcs) $(stdlib_rt) $(stdlib_io) $(stdlib_bufio) $(stdlib_strings) $(stdlib_types) $(stdlib_fmt) $(stdlib_sort) $(stdlib_strio)
+$(HARECACHE)/hare/lex/hare_lex-any.ssa: $(stdlib_hare_lex_any_srcs) $(stdlib_rt) $(stdlib_io_$(PLATFORM)) $(stdlib_bufio_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_types_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM)) $(stdlib_sort_$(PLATFORM)) $(stdlib_strio_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/hare/lex
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhare::lex \
@@ -689,7 +900,7 @@ stdlib_hare_module_any_srcs= \
$(STDLIB)/hare/module/scan.ha \
$(STDLIB)/hare/module/manifest.ha
-$(HARECACHE)/hare/module/hare_module-any.ssa: $(stdlib_hare_module_any_srcs) $(stdlib_rt) $(stdlib_hare_ast) $(stdlib_hare_lex) $(stdlib_hare_parse) $(stdlib_hare_unparse) $(stdlib_strio) $(stdlib_fs) $(stdlib_io) $(stdlib_strings) $(stdlib_hash) $(stdlib_crypto_sha256) $(stdlib_dirs) $(stdlib_bytes) $(stdlib_encoding_utf8) $(stdlib_ascii) $(stdlib_fmt) $(stdlib_time) $(stdlib_slice) $(stdlib_bufio) $(stdlib_strconv) $(stdlib_os) $(stdlib_encoding_hex) $(stdlib_sort) $(stdlib_errors) $(stdlib_temp)
+$(HARECACHE)/hare/module/hare_module-any.ssa: $(stdlib_hare_module_any_srcs) $(stdlib_rt) $(stdlib_hare_ast_$(PLATFORM)) $(stdlib_hare_lex_$(PLATFORM)) $(stdlib_hare_parse_$(PLATFORM)) $(stdlib_hare_unparse_$(PLATFORM)) $(stdlib_strio_$(PLATFORM)) $(stdlib_fs_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_crypto_sha256_$(PLATFORM)) $(stdlib_dirs_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) $(stdlib_encoding_utf8_$(PLATFORM)) $(stdlib_ascii_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM)) $(stdlib_time_$(PLATFORM)) $(stdlib_slice_$(PLATFORM)) $(stdlib_bufio_$(PLATFORM)) $(stdlib_strconv_$(PLATFORM)) $(stdlib_os_$(PLATFORM)) $(stdlib_encoding_hex_$(PLATFORM)) $(stdlib_sort_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_temp_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/hare/module
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhare::module \
@@ -705,7 +916,7 @@ stdlib_hare_parse_any_srcs= \
$(STDLIB)/hare/parse/type.ha \
$(STDLIB)/hare/parse/unit.ha
-$(HARECACHE)/hare/parse/hare_parse-any.ssa: $(stdlib_hare_parse_any_srcs) $(stdlib_rt) $(stdlib_hare_ast) $(stdlib_hare_lex) $(stdlib_hare_unparse) $(stdlib_fmt)
+$(HARECACHE)/hare/parse/hare_parse-any.ssa: $(stdlib_hare_parse_any_srcs) $(stdlib_rt) $(stdlib_hare_ast_$(PLATFORM)) $(stdlib_hare_lex_$(PLATFORM)) $(stdlib_hare_unparse_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/hare/parse
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhare::parse \
@@ -721,7 +932,7 @@ stdlib_hare_types_any_srcs= \
$(STDLIB)/hare/types/store.ha \
$(STDLIB)/hare/types/types.ha
-$(HARECACHE)/hare/types/hare_types-any.ssa: $(stdlib_hare_types_any_srcs) $(stdlib_rt) $(stdlib_hare_ast) $(stdlib_hare_parse) $(stdlib_hash) $(stdlib_hash_fnv) $(stdlib_endian)
+$(HARECACHE)/hare/types/hare_types-any.ssa: $(stdlib_hare_types_any_srcs) $(stdlib_rt) $(stdlib_hare_ast_$(PLATFORM)) $(stdlib_hare_parse_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_hash_fnv_$(PLATFORM)) $(stdlib_endian_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/hare/types
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhare::types \
@@ -738,7 +949,7 @@ stdlib_hare_unit_any_srcs= \
$(STDLIB)/hare/unit/scope.ha \
$(STDLIB)/hare/unit/unit.ha
-$(HARECACHE)/hare/unit/hare_unit-any.ssa: $(stdlib_hare_unit_any_srcs) $(stdlib_rt) $(stdlib_hare_ast) $(stdlib_hare_types) $(stdlib_hash) $(stdlib_hash_fnv) $(stdlib_strings) $(stdlib_hare_lex) $(stdlib_bufio) $(stdlib_hare_parse)
+$(HARECACHE)/hare/unit/hare_unit-any.ssa: $(stdlib_hare_unit_any_srcs) $(stdlib_rt) $(stdlib_hare_ast_$(PLATFORM)) $(stdlib_hare_types_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_hash_fnv_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_hare_lex_$(PLATFORM)) $(stdlib_bufio_$(PLATFORM)) $(stdlib_hare_parse_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/hare/unit
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhare::unit \
@@ -754,7 +965,7 @@ stdlib_hare_unparse_any_srcs= \
$(STDLIB)/hare/unparse/unit.ha \
$(STDLIB)/hare/unparse/util.ha
-$(HARECACHE)/hare/unparse/hare_unparse-any.ssa: $(stdlib_hare_unparse_any_srcs) $(stdlib_rt) $(stdlib_fmt) $(stdlib_io) $(stdlib_strio) $(stdlib_hare_ast)
+$(HARECACHE)/hare/unparse/hare_unparse-any.ssa: $(stdlib_hare_unparse_any_srcs) $(stdlib_rt) $(stdlib_fmt_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_strio_$(PLATFORM)) $(stdlib_hare_ast_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/hare/unparse
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhare::unparse \
@@ -764,7 +975,7 @@ $(HARECACHE)/hare/unparse/hare_unparse-any.ssa: $(stdlib_hare_unparse_any_srcs)
stdlib_hash_any_srcs= \
$(STDLIB)/hash/hash.ha
-$(HARECACHE)/hash/hash-any.ssa: $(stdlib_hash_any_srcs) $(stdlib_rt) $(stdlib_io) $(stdlib_fmt)
+$(HARECACHE)/hash/hash-any.ssa: $(stdlib_hash_any_srcs) $(stdlib_rt) $(stdlib_io_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/hash
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhash \
@@ -774,7 +985,7 @@ $(HARECACHE)/hash/hash-any.ssa: $(stdlib_hash_any_srcs) $(stdlib_rt) $(stdlib_io
stdlib_hash_adler32_any_srcs= \
$(STDLIB)/hash/adler32/adler32.ha
-$(HARECACHE)/hash/adler32/hash_adler32-any.ssa: $(stdlib_hash_adler32_any_srcs) $(stdlib_rt) $(stdlib_endian) $(stdlib_hash) $(stdlib_io) $(stdlib_strings)
+$(HARECACHE)/hash/adler32/hash_adler32-any.ssa: $(stdlib_hash_adler32_any_srcs) $(stdlib_rt) $(stdlib_endian_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/hash/adler32
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhash::adler32 \
@@ -784,7 +995,7 @@ $(HARECACHE)/hash/adler32/hash_adler32-any.ssa: $(stdlib_hash_adler32_any_srcs)
stdlib_hash_crc16_any_srcs= \
$(STDLIB)/hash/crc16/crc16.ha
-$(HARECACHE)/hash/crc16/hash_crc16-any.ssa: $(stdlib_hash_crc16_any_srcs) $(stdlib_rt) $(stdlib_endian) $(stdlib_hash) $(stdlib_io) $(stdlib_strings)
+$(HARECACHE)/hash/crc16/hash_crc16-any.ssa: $(stdlib_hash_crc16_any_srcs) $(stdlib_rt) $(stdlib_endian_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/hash/crc16
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhash::crc16 \
@@ -794,7 +1005,7 @@ $(HARECACHE)/hash/crc16/hash_crc16-any.ssa: $(stdlib_hash_crc16_any_srcs) $(stdl
stdlib_hash_crc32_any_srcs= \
$(STDLIB)/hash/crc32/crc32.ha
-$(HARECACHE)/hash/crc32/hash_crc32-any.ssa: $(stdlib_hash_crc32_any_srcs) $(stdlib_rt) $(stdlib_endian) $(stdlib_hash) $(stdlib_io) $(stdlib_strings)
+$(HARECACHE)/hash/crc32/hash_crc32-any.ssa: $(stdlib_hash_crc32_any_srcs) $(stdlib_rt) $(stdlib_endian_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/hash/crc32
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhash::crc32 \
@@ -804,7 +1015,7 @@ $(HARECACHE)/hash/crc32/hash_crc32-any.ssa: $(stdlib_hash_crc32_any_srcs) $(stdl
stdlib_hash_crc64_any_srcs= \
$(STDLIB)/hash/crc64/crc64.ha
-$(HARECACHE)/hash/crc64/hash_crc64-any.ssa: $(stdlib_hash_crc64_any_srcs) $(stdlib_rt) $(stdlib_endian) $(stdlib_hash) $(stdlib_io) $(stdlib_strings)
+$(HARECACHE)/hash/crc64/hash_crc64-any.ssa: $(stdlib_hash_crc64_any_srcs) $(stdlib_rt) $(stdlib_endian_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/hash/crc64
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhash::crc64 \
@@ -814,7 +1025,7 @@ $(HARECACHE)/hash/crc64/hash_crc64-any.ssa: $(stdlib_hash_crc64_any_srcs) $(stdl
stdlib_hash_fnv_any_srcs= \
$(STDLIB)/hash/fnv/fnv.ha
-$(HARECACHE)/hash/fnv/hash_fnv-any.ssa: $(stdlib_hash_fnv_any_srcs) $(stdlib_rt) $(stdlib_hash) $(stdlib_io) $(stdlib_strings)
+$(HARECACHE)/hash/fnv/hash_fnv-any.ssa: $(stdlib_hash_fnv_any_srcs) $(stdlib_rt) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/hash/fnv
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhash::fnv \
@@ -835,12 +1046,33 @@ stdlib_io_linux_srcs= \
$(STDLIB)/io/tee.ha \
$(STDLIB)/io/types.ha
-$(HARECACHE)/io/io-linux.ssa: $(stdlib_io_linux_srcs) $(stdlib_rt) $(stdlib_strings) $(stdlib_errors)
+# io (+freebsd)
+stdlib_io_freebsd_srcs= \
+ $(STDLIB)/io/arch+$(ARCH).ha \
+ $(STDLIB)/io/println+freebsd.ha \
+ $(STDLIB)/io/+freebsd/file.ha \
+ $(STDLIB)/io/copy.ha \
+ $(STDLIB)/io/drain.ha \
+ $(STDLIB)/io/empty.ha \
+ $(STDLIB)/io/filestream.ha \
+ $(STDLIB)/io/handle.ha \
+ $(STDLIB)/io/limit.ha \
+ $(STDLIB)/io/stream.ha \
+ $(STDLIB)/io/tee.ha \
+ $(STDLIB)/io/types.ha
+
+$(HARECACHE)/io/io-linux.ssa: $(stdlib_io_linux_srcs) $(stdlib_rt) $(stdlib_strings_$(PLATFORM)) $(stdlib_errors_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/io
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nio \
-t$(HARECACHE)/io/io.td $(stdlib_io_linux_srcs)
+$(HARECACHE)/io/io-freebsd.ssa: $(stdlib_io_freebsd_srcs) $(stdlib_rt) $(stdlib_strings_$(PLATFORM)) $(stdlib_errors_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/io
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nio \
+ -t$(HARECACHE)/io/io.td $(stdlib_io_freebsd_srcs)
+
# iobus::io_uring (+linux)
stdlib_iobus_io_uring_linux_srcs= \
$(STDLIB)/iobus/io_uring/bus.ha \
@@ -849,7 +1081,7 @@ stdlib_iobus_io_uring_linux_srcs= \
$(STDLIB)/iobus/io_uring/pool.ha \
$(STDLIB)/iobus/io_uring/types.ha
-$(HARECACHE)/iobus/io_uring/iobus_io_uring-linux.ssa: $(stdlib_iobus_io_uring_linux_srcs) $(stdlib_rt) $(stdlib_errors) $(stdlib_io) $(stdlib_linux_io_uring) $(stdlib_net_ip) $(stdlib_unix_poll)
+$(HARECACHE)/iobus/io_uring/iobus_io_uring-linux.ssa: $(stdlib_iobus_io_uring_linux_srcs) $(stdlib_rt) $(stdlib_errors_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_linux_io_uring_$(PLATFORM)) $(stdlib_net_ip_$(PLATFORM)) $(stdlib_unix_poll_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/iobus/io_uring
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Niobus::io_uring \
@@ -860,7 +1092,7 @@ stdlib_linux_linux_srcs= \
$(STDLIB)/linux/start.ha \
$(STDLIB)/linux/env.ha
-$(HARECACHE)/linux/linux-linux.ssa: $(stdlib_linux_linux_srcs) $(stdlib_rt) $(stdlib_format_elf)
+$(HARECACHE)/linux/linux-linux.ssa: $(stdlib_linux_linux_srcs) $(stdlib_rt) $(stdlib_format_elf_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/linux
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nlinux \
@@ -870,7 +1102,7 @@ $(HARECACHE)/linux/linux-linux.ssa: $(stdlib_linux_linux_srcs) $(stdlib_rt) $(st
stdlib_linux_signalfd_linux_srcs= \
$(STDLIB)/linux/signalfd/signalfd.ha
-$(HARECACHE)/linux/signalfd/linux_signalfd-linux.ssa: $(stdlib_linux_signalfd_linux_srcs) $(stdlib_rt) $(stdlib_errors)
+$(HARECACHE)/linux/signalfd/linux_signalfd-linux.ssa: $(stdlib_linux_signalfd_linux_srcs) $(stdlib_rt) $(stdlib_errors_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/linux/signalfd
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nlinux::signalfd \
@@ -885,7 +1117,7 @@ stdlib_linux_io_uring_linux_srcs= \
$(STDLIB)/linux/io_uring/sqe.ha \
$(STDLIB)/linux/io_uring/uring.ha
-$(HARECACHE)/linux/io_uring/linux_io_uring-linux.ssa: $(stdlib_linux_io_uring_linux_srcs) $(stdlib_rt) $(stdlib_errors) $(stdlib_types)
+$(HARECACHE)/linux/io_uring/linux_io_uring-linux.ssa: $(stdlib_linux_io_uring_linux_srcs) $(stdlib_rt) $(stdlib_errors_$(PLATFORM)) $(stdlib_types_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/linux/io_uring
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nlinux::io_uring \
@@ -895,7 +1127,7 @@ $(HARECACHE)/linux/io_uring/linux_io_uring-linux.ssa: $(stdlib_linux_io_uring_li
stdlib_linux_vdso_linux_srcs= \
$(STDLIB)/linux/vdso/vdso.ha
-$(HARECACHE)/linux/vdso/linux_vdso-linux.ssa: $(stdlib_linux_vdso_linux_srcs) $(stdlib_rt) $(stdlib_linux) $(stdlib_strings) $(stdlib_format_elf)
+$(HARECACHE)/linux/vdso/linux_vdso-linux.ssa: $(stdlib_linux_vdso_linux_srcs) $(stdlib_rt) $(stdlib_linux_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_format_elf_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/linux/vdso
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nlinux::vdso \
@@ -909,7 +1141,7 @@ stdlib_math_any_srcs= \
$(STDLIB)/math/uints.ha \
$(STDLIB)/math/trig.ha
-$(HARECACHE)/math/math-any.ssa: $(stdlib_math_any_srcs) $(stdlib_rt) $(stdlib_types)
+$(HARECACHE)/math/math-any.ssa: $(stdlib_math_any_srcs) $(stdlib_rt) $(stdlib_types_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/math
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nmath \
@@ -921,12 +1153,24 @@ stdlib_net_linux_srcs= \
$(STDLIB)/net/errors.ha \
$(STDLIB)/net/listener.ha
-$(HARECACHE)/net/net-linux.ssa: $(stdlib_net_linux_srcs) $(stdlib_rt) $(stdlib_io) $(stdlib_os) $(stdlib_strings) $(stdlib_net_ip) $(stdlib_errors) $(stdlib_rt) $(stdlib_fmt)
+$(HARECACHE)/net/net-linux.ssa: $(stdlib_net_linux_srcs) $(stdlib_rt) $(stdlib_io_$(PLATFORM)) $(stdlib_os_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_net_ip_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_rt_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/net
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nnet \
-t$(HARECACHE)/net/net.td $(stdlib_net_linux_srcs)
+# net (+freebsd)
+stdlib_net_freebsd_srcs= \
+ $(STDLIB)/net/+freebsd.ha \
+ $(STDLIB)/net/errors.ha \
+ $(STDLIB)/net/listener.ha
+
+$(HARECACHE)/net/net-freebsd.ssa: $(stdlib_net_freebsd_srcs) $(stdlib_rt) $(stdlib_io_$(PLATFORM)) $(stdlib_os_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_net_ip_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_rt_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/net
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nnet \
+ -t$(HARECACHE)/net/net.td $(stdlib_net_freebsd_srcs)
+
# net::dial (+any)
stdlib_net_dial_any_srcs= \
$(STDLIB)/net/dial/registry.ha \
@@ -934,7 +1178,7 @@ stdlib_net_dial_any_srcs= \
$(STDLIB)/net/dial/ip.ha \
$(STDLIB)/net/dial/resolve.ha
-$(HARECACHE)/net/dial/net_dial-any.ssa: $(stdlib_net_dial_any_srcs) $(stdlib_rt) $(stdlib_io) $(stdlib_net) $(stdlib_net_ip) $(stdlib_net_tcp) $(stdlib_net_udp) $(stdlib_net_dns) $(stdlib_crypto_random) $(stdlib_strconv) $(stdlib_strings) $(stdlib_unix_hosts)
+$(HARECACHE)/net/dial/net_dial-any.ssa: $(stdlib_net_dial_any_srcs) $(stdlib_rt) $(stdlib_io_$(PLATFORM)) $(stdlib_net_$(PLATFORM)) $(stdlib_net_ip_$(PLATFORM)) $(stdlib_net_tcp_$(PLATFORM)) $(stdlib_net_udp_$(PLATFORM)) $(stdlib_net_dns_$(PLATFORM)) $(stdlib_crypto_random_$(PLATFORM)) $(stdlib_strconv_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_unix_hosts_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/net/dial
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nnet::dial \
@@ -948,7 +1192,7 @@ stdlib_net_dns_any_srcs= \
$(STDLIB)/net/dns/query.ha \
$(STDLIB)/net/dns/types.ha
-$(HARECACHE)/net/dns/net_dns-any.ssa: $(stdlib_net_dns_any_srcs) $(stdlib_rt) $(stdlib_ascii) $(stdlib_endian) $(stdlib_net) $(stdlib_net_udp) $(stdlib_net_ip) $(stdlib_fmt) $(stdlib_strings) $(stdlib_unix_resolvconf) $(stdlib_unix_poll) $(stdlib_rt) $(stdlib_time) $(stdlib_errors)
+$(HARECACHE)/net/dns/net_dns-any.ssa: $(stdlib_net_dns_any_srcs) $(stdlib_rt) $(stdlib_ascii_$(PLATFORM)) $(stdlib_endian_$(PLATFORM)) $(stdlib_net_$(PLATFORM)) $(stdlib_net_udp_$(PLATFORM)) $(stdlib_net_ip_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_unix_resolvconf_$(PLATFORM)) $(stdlib_unix_poll_$(PLATFORM)) $(stdlib_rt_$(PLATFORM)) $(stdlib_time_$(PLATFORM)) $(stdlib_errors_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/net/dns
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nnet::dns \
@@ -956,38 +1200,72 @@ $(HARECACHE)/net/dns/net_dns-any.ssa: $(stdlib_net_dns_any_srcs) $(stdlib_rt) $(
# net::ip (+linux)
stdlib_net_ip_linux_srcs= \
- $(STDLIB)/net/ip/ip.ha \
- $(STDLIB)/net/ip/+linux.ha
+ $(STDLIB)/net/ip/+linux.ha \
+ $(STDLIB)/net/ip/ip.ha
-$(HARECACHE)/net/ip/net_ip-linux.ssa: $(stdlib_net_ip_linux_srcs) $(stdlib_rt) $(stdlib_bytes) $(stdlib_io) $(stdlib_strconv) $(stdlib_strings) $(stdlib_strio) $(stdlib_fmt)
+# net::ip (+freebsd)
+stdlib_net_ip_freebsd_srcs= \
+ $(STDLIB)/net/ip/+freebsd.ha \
+ $(STDLIB)/net/ip/ip.ha
+
+$(HARECACHE)/net/ip/net_ip-linux.ssa: $(stdlib_net_ip_linux_srcs) $(stdlib_rt) $(stdlib_bytes_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_strconv_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_strio_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/net/ip
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nnet::ip \
-t$(HARECACHE)/net/ip/net_ip.td $(stdlib_net_ip_linux_srcs)
+$(HARECACHE)/net/ip/net_ip-freebsd.ssa: $(stdlib_net_ip_freebsd_srcs) $(stdlib_rt) $(stdlib_bytes_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_strconv_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_strio_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/net/ip
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nnet::ip \
+ -t$(HARECACHE)/net/ip/net_ip.td $(stdlib_net_ip_freebsd_srcs)
+
# net::tcp (+linux)
stdlib_net_tcp_linux_srcs= \
$(STDLIB)/net/tcp/+linux.ha \
$(STDLIB)/net/tcp/listener.ha \
$(STDLIB)/net/tcp/options.ha
-$(HARECACHE)/net/tcp/net_tcp-linux.ssa: $(stdlib_net_tcp_linux_srcs) $(stdlib_rt) $(stdlib_io) $(stdlib_net) $(stdlib_net_ip) $(stdlib_os) $(stdlib_rt)
+$(HARECACHE)/net/tcp/net_tcp-linux.ssa: $(stdlib_net_tcp_linux_srcs) $(stdlib_rt) $(stdlib_io_$(PLATFORM)) $(stdlib_net_$(PLATFORM)) $(stdlib_net_ip_$(PLATFORM)) $(stdlib_os_$(PLATFORM)) $(stdlib_rt_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/net/tcp
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nnet::tcp \
-t$(HARECACHE)/net/tcp/net_tcp.td $(stdlib_net_tcp_linux_srcs)
+# net::tcp (+freebsd)
+stdlib_net_tcp_freebsd_srcs= \
+ $(STDLIB)/net/tcp/+freebsd.ha \
+ $(STDLIB)/net/tcp/listener.ha \
+ $(STDLIB)/net/tcp/options.ha
+
+$(HARECACHE)/net/tcp/net_tcp-freebsd.ssa: $(stdlib_net_tcp_freebsd_srcs) $(stdlib_rt) $(stdlib_io_$(PLATFORM)) $(stdlib_net_$(PLATFORM)) $(stdlib_net_ip_$(PLATFORM)) $(stdlib_os_$(PLATFORM)) $(stdlib_rt_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/net/tcp
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nnet::tcp \
+ -t$(HARECACHE)/net/tcp/net_tcp.td $(stdlib_net_tcp_freebsd_srcs)
+
# net::udp (+linux)
stdlib_net_udp_linux_srcs= \
$(STDLIB)/net/udp/+linux.ha \
$(STDLIB)/net/udp/options.ha
-$(HARECACHE)/net/udp/net_udp-linux.ssa: $(stdlib_net_udp_linux_srcs) $(stdlib_rt) $(stdlib_net) $(stdlib_net_ip) $(stdlib_errors) $(stdlib_rt) $(stdlib_os) $(stdlib_io)
+$(HARECACHE)/net/udp/net_udp-linux.ssa: $(stdlib_net_udp_linux_srcs) $(stdlib_rt) $(stdlib_net_$(PLATFORM)) $(stdlib_net_ip_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_rt_$(PLATFORM)) $(stdlib_os_$(PLATFORM)) $(stdlib_io_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/net/udp
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nnet::udp \
-t$(HARECACHE)/net/udp/net_udp.td $(stdlib_net_udp_linux_srcs)
+# net::udp (+freebsd)
+stdlib_net_udp_freebsd_srcs= \
+ $(STDLIB)/net/udp/+freebsd.ha \
+ $(STDLIB)/net/udp/options.ha
+
+$(HARECACHE)/net/udp/net_udp-freebsd.ssa: $(stdlib_net_udp_freebsd_srcs) $(stdlib_rt) $(stdlib_net_$(PLATFORM)) $(stdlib_net_ip_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_rt_$(PLATFORM)) $(stdlib_os_$(PLATFORM)) $(stdlib_io_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/net/udp
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nnet::udp \
+ -t$(HARECACHE)/net/udp/net_udp.td $(stdlib_net_udp_freebsd_srcs)
+
# net::unix (+linux)
stdlib_net_unix_linux_srcs= \
$(STDLIB)/net/unix/+linux.ha \
@@ -996,12 +1274,26 @@ stdlib_net_unix_linux_srcs= \
$(STDLIB)/net/unix/listener.ha \
$(STDLIB)/net/unix/options.ha
-$(HARECACHE)/net/unix/net_unix-linux.ssa: $(stdlib_net_unix_linux_srcs) $(stdlib_rt) $(stdlib_net) $(stdlib_errors) $(stdlib_os) $(stdlib_io) $(stdlib_strings) $(stdlib_types) $(stdlib_fmt) $(stdlib_net_dial)
+$(HARECACHE)/net/unix/net_unix-linux.ssa: $(stdlib_net_unix_linux_srcs) $(stdlib_rt) $(stdlib_net_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_os_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_types_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM)) $(stdlib_net_dial_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/net/unix
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nnet::unix \
-t$(HARECACHE)/net/unix/net_unix.td $(stdlib_net_unix_linux_srcs)
+# net::unix (+freebsd)
+stdlib_net_unix_freebsd_srcs= \
+ $(STDLIB)/net/unix/+freebsd.ha \
+ $(STDLIB)/net/unix/addr.ha \
+ $(STDLIB)/net/unix/dial.ha \
+ $(STDLIB)/net/unix/listener.ha \
+ $(STDLIB)/net/unix/options.ha
+
+$(HARECACHE)/net/unix/net_unix-freebsd.ssa: $(stdlib_net_unix_freebsd_srcs) $(stdlib_rt) $(stdlib_net_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_os_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_types_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM)) $(stdlib_net_dial_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/net/unix
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nnet::unix \
+ -t$(HARECACHE)/net/unix/net_unix.td $(stdlib_net_unix_freebsd_srcs)
+
# math::random (+any)
stdlib_math_random_any_srcs= \
$(STDLIB)/math/random/random.ha
@@ -1021,12 +1313,27 @@ stdlib_os_linux_srcs= \
$(STDLIB)/os/+linux/fs.ha \
$(STDLIB)/os/fs.ha
-$(HARECACHE)/os/os-linux.ssa: $(stdlib_os_linux_srcs) $(stdlib_rt) $(stdlib_io) $(stdlib_strings) $(stdlib_types) $(stdlib_fs) $(stdlib_encoding_utf8) $(stdlib_bytes) $(stdlib_bufio) $(stdlib_errors)
+$(HARECACHE)/os/os-linux.ssa: $(stdlib_os_linux_srcs) $(stdlib_rt) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_types_$(PLATFORM)) $(stdlib_fs_$(PLATFORM)) $(stdlib_encoding_utf8_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) $(stdlib_bufio_$(PLATFORM)) $(stdlib_errors_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/os
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nos \
-t$(HARECACHE)/os/os.td $(stdlib_os_linux_srcs)
+# os (+freebsd)
+stdlib_os_freebsd_srcs= \
+ $(STDLIB)/os/+freebsd/environ.ha \
+ $(STDLIB)/os/+freebsd/exit.ha \
+ $(STDLIB)/os/+freebsd/dirfdfs.ha \
+ $(STDLIB)/os/+freebsd/stdfd.ha \
+ $(STDLIB)/os/+freebsd/fs.ha \
+ $(STDLIB)/os/fs.ha
+
+$(HARECACHE)/os/os-freebsd.ssa: $(stdlib_os_freebsd_srcs) $(stdlib_rt) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_types_$(PLATFORM)) $(stdlib_fs_$(PLATFORM)) $(stdlib_encoding_utf8_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) $(stdlib_bufio_$(PLATFORM)) $(stdlib_errors_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/os
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nos \
+ -t$(HARECACHE)/os/os.td $(stdlib_os_freebsd_srcs)
+
# os::exec (+linux)
stdlib_os_exec_linux_srcs= \
$(STDLIB)/os/exec/exec+linux.ha \
@@ -1034,12 +1341,25 @@ stdlib_os_exec_linux_srcs= \
$(STDLIB)/os/exec/types.ha \
$(STDLIB)/os/exec/cmd.ha
-$(HARECACHE)/os/exec/os_exec-linux.ssa: $(stdlib_os_exec_linux_srcs) $(stdlib_rt) $(stdlib_os) $(stdlib_strings) $(stdlib_fmt) $(stdlib_bytes) $(stdlib_path) $(stdlib_errors)
+$(HARECACHE)/os/exec/os_exec-linux.ssa: $(stdlib_os_exec_linux_srcs) $(stdlib_rt) $(stdlib_os_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) $(stdlib_path_$(PLATFORM)) $(stdlib_errors_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/os/exec
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nos::exec \
-t$(HARECACHE)/os/exec/os_exec.td $(stdlib_os_exec_linux_srcs)
+# os::exec (+freebsd)
+stdlib_os_exec_freebsd_srcs= \
+ $(STDLIB)/os/exec/exec+freebsd.ha \
+ $(STDLIB)/os/exec/process+freebsd.ha \
+ $(STDLIB)/os/exec/types.ha \
+ $(STDLIB)/os/exec/cmd.ha
+
+$(HARECACHE)/os/exec/os_exec-freebsd.ssa: $(stdlib_os_exec_freebsd_srcs) $(stdlib_rt) $(stdlib_os_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) $(stdlib_path_$(PLATFORM)) $(stdlib_errors_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/os/exec
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nos::exec \
+ -t$(HARECACHE)/os/exec/os_exec.td $(stdlib_os_exec_freebsd_srcs)
+
# path (+any)
stdlib_path_any_srcs= \
$(STDLIB)/path/+$(PLATFORM).ha \
@@ -1048,7 +1368,7 @@ stdlib_path_any_srcs= \
$(STDLIB)/path/names.ha \
$(STDLIB)/path/iter.ha
-$(HARECACHE)/path/path-any.ssa: $(stdlib_path_any_srcs) $(stdlib_rt) $(stdlib_strings) $(stdlib_bufio) $(stdlib_bytes)
+$(HARECACHE)/path/path-any.ssa: $(stdlib_path_any_srcs) $(stdlib_rt) $(stdlib_strings_$(PLATFORM)) $(stdlib_bufio_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/path
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Npath \
@@ -1059,7 +1379,7 @@ stdlib_slice_any_srcs= \
$(STDLIB)/slice/reverse.ha \
$(STDLIB)/slice/void.ha
-$(HARECACHE)/slice/slice-any.ssa: $(stdlib_slice_any_srcs) $(stdlib_rt) $(stdlib_types)
+$(HARECACHE)/slice/slice-any.ssa: $(stdlib_slice_any_srcs) $(stdlib_rt) $(stdlib_types_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/slice
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nslice \
@@ -1088,7 +1408,7 @@ stdlib_strconv_any_srcs= \
$(STDLIB)/strconv/stof.ha \
$(STDLIB)/strconv/stof_data.ha
-$(HARECACHE)/strconv/strconv-any.ssa: $(stdlib_strconv_any_srcs) $(stdlib_rt) $(stdlib_types) $(stdlib_strings) $(stdlib_ascii) $(stdlib_math)
+$(HARECACHE)/strconv/strconv-any.ssa: $(stdlib_strconv_any_srcs) $(stdlib_rt) $(stdlib_types_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_ascii_$(PLATFORM)) $(stdlib_math_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/strconv
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nstrconv \
@@ -1108,7 +1428,7 @@ stdlib_strings_any_srcs= \
$(STDLIB)/strings/index.ha \
$(STDLIB)/strings/trim.ha
-$(HARECACHE)/strings/strings-any.ssa: $(stdlib_strings_any_srcs) $(stdlib_rt) $(stdlib_bytes) $(stdlib_encoding_utf8) $(stdlib_types)
+$(HARECACHE)/strings/strings-any.ssa: $(stdlib_strings_any_srcs) $(stdlib_rt) $(stdlib_bytes_$(PLATFORM)) $(stdlib_encoding_utf8_$(PLATFORM)) $(stdlib_types_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/strings
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nstrings \
@@ -1120,7 +1440,7 @@ stdlib_strio_any_srcs= \
$(STDLIB)/strio/fixed.ha \
$(STDLIB)/strio/ops.ha
-$(HARECACHE)/strio/strio-any.ssa: $(stdlib_strio_any_srcs) $(stdlib_rt) $(stdlib_io) $(stdlib_strings) $(stdlib_encoding_utf8) $(stdlib_errors)
+$(HARECACHE)/strio/strio-any.ssa: $(stdlib_strio_any_srcs) $(stdlib_rt) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_encoding_utf8_$(PLATFORM)) $(stdlib_errors_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/strio
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nstrio \
@@ -1130,12 +1450,22 @@ $(HARECACHE)/strio/strio-any.ssa: $(stdlib_strio_any_srcs) $(stdlib_rt) $(stdlib
stdlib_temp_linux_srcs= \
$(STDLIB)/temp/+linux.ha
-$(HARECACHE)/temp/temp-linux.ssa: $(stdlib_temp_linux_srcs) $(stdlib_rt) $(stdlib_crypto_random) $(stdlib_encoding_hex) $(stdlib_fs) $(stdlib_io) $(stdlib_os) $(stdlib_path) $(stdlib_strio) $(stdlib_fmt) $(stdlib_strings)
+$(HARECACHE)/temp/temp-linux.ssa: $(stdlib_temp_linux_srcs) $(stdlib_rt) $(stdlib_crypto_random_$(PLATFORM)) $(stdlib_encoding_hex_$(PLATFORM)) $(stdlib_fs_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_os_$(PLATFORM)) $(stdlib_path_$(PLATFORM)) $(stdlib_strio_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM)) $(stdlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/temp
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ntemp \
-t$(HARECACHE)/temp/temp.td $(stdlib_temp_linux_srcs)
+# temp (+freebsd)
+stdlib_temp_freebsd_srcs= \
+ $(STDLIB)/temp/+freebsd.ha
+
+$(HARECACHE)/temp/temp-freebsd.ssa: $(stdlib_temp_freebsd_srcs) $(stdlib_rt) $(stdlib_crypto_random_$(PLATFORM)) $(stdlib_encoding_hex_$(PLATFORM)) $(stdlib_fs_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_os_$(PLATFORM)) $(stdlib_path_$(PLATFORM)) $(stdlib_strio_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM)) $(stdlib_strings_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/temp
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ntemp \
+ -t$(HARECACHE)/temp/temp.td $(stdlib_temp_freebsd_srcs)
+
# time (+linux)
stdlib_time_linux_srcs= \
$(STDLIB)/time/+linux/functions.ha \
@@ -1143,12 +1473,24 @@ stdlib_time_linux_srcs= \
$(STDLIB)/time/arithm.ha \
$(STDLIB)/time/types.ha
-$(HARECACHE)/time/time-linux.ssa: $(stdlib_time_linux_srcs) $(stdlib_rt) $(stdlib_linux_vdso)
+$(HARECACHE)/time/time-linux.ssa: $(stdlib_time_linux_srcs) $(stdlib_rt) $(stdlib_linux_vdso_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/time
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ntime \
-t$(HARECACHE)/time/time.td $(stdlib_time_linux_srcs)
+# time (+freebsd)
+stdlib_time_freebsd_srcs= \
+ $(STDLIB)/time/+freebsd/functions.ha \
+ $(STDLIB)/time/arithm.ha \
+ $(STDLIB)/time/types.ha
+
+$(HARECACHE)/time/time-freebsd.ssa: $(stdlib_time_freebsd_srcs) $(stdlib_rt)
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/time
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ntime \
+ -t$(HARECACHE)/time/time.td $(stdlib_time_freebsd_srcs)
+
# types (+any)
stdlib_types_any_srcs= \
$(STDLIB)/types/limits.ha \
@@ -1171,17 +1513,31 @@ stdlib_unix_linux_srcs= \
$(STDLIB)/unix/getuid.ha \
$(STDLIB)/unix/setuid.ha
-$(HARECACHE)/unix/unix-linux.ssa: $(stdlib_unix_linux_srcs) $(stdlib_rt) $(stdlib_errors) $(stdlib_fs)
+$(HARECACHE)/unix/unix-linux.ssa: $(stdlib_unix_linux_srcs) $(stdlib_rt) $(stdlib_errors_$(PLATFORM)) $(stdlib_fs_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/unix
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nunix \
-t$(HARECACHE)/unix/unix.td $(stdlib_unix_linux_srcs)
+# unix (+freebsd)
+stdlib_unix_freebsd_srcs= \
+ $(STDLIB)/unix/+freebsd/nice.ha \
+ $(STDLIB)/unix/+freebsd/pipe.ha \
+ $(STDLIB)/unix/+freebsd/umask.ha \
+ $(STDLIB)/unix/getuid.ha \
+ $(STDLIB)/unix/setuid.ha
+
+$(HARECACHE)/unix/unix-freebsd.ssa: $(stdlib_unix_freebsd_srcs) $(stdlib_rt) $(stdlib_errors_$(PLATFORM)) $(stdlib_fs_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/unix
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nunix \
+ -t$(HARECACHE)/unix/unix.td $(stdlib_unix_freebsd_srcs)
+
# unix::hosts (+any)
stdlib_unix_hosts_any_srcs= \
$(STDLIB)/unix/hosts/lookup.ha
-$(HARECACHE)/unix/hosts/unix_hosts-any.ssa: $(stdlib_unix_hosts_any_srcs) $(stdlib_rt) $(stdlib_os) $(stdlib_io) $(stdlib_bufio) $(stdlib_net_ip) $(stdlib_strings)
+$(HARECACHE)/unix/hosts/unix_hosts-any.ssa: $(stdlib_unix_hosts_any_srcs) $(stdlib_rt) $(stdlib_os_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_bufio_$(PLATFORM)) $(stdlib_net_ip_$(PLATFORM)) $(stdlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/unix/hosts
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nunix::hosts \
@@ -1193,7 +1549,7 @@ stdlib_unix_passwd_any_srcs= \
$(STDLIB)/unix/passwd/passwd.ha \
$(STDLIB)/unix/passwd/types.ha
-$(HARECACHE)/unix/passwd/unix_passwd-any.ssa: $(stdlib_unix_passwd_any_srcs) $(stdlib_rt) $(stdlib_bufio) $(stdlib_io) $(stdlib_os) $(stdlib_strconv) $(stdlib_strings)
+$(HARECACHE)/unix/passwd/unix_passwd-any.ssa: $(stdlib_unix_passwd_any_srcs) $(stdlib_rt) $(stdlib_bufio_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_os_$(PLATFORM)) $(stdlib_strconv_$(PLATFORM)) $(stdlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/unix/passwd
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nunix::passwd \
@@ -1203,17 +1559,27 @@ $(HARECACHE)/unix/passwd/unix_passwd-any.ssa: $(stdlib_unix_passwd_any_srcs) $(s
stdlib_unix_poll_linux_srcs= \
$(STDLIB)/unix/poll/+linux.ha
-$(HARECACHE)/unix/poll/unix_poll-linux.ssa: $(stdlib_unix_poll_linux_srcs) $(stdlib_rt) $(stdlib_rt) $(stdlib_errors) $(stdlib_time)
+$(HARECACHE)/unix/poll/unix_poll-linux.ssa: $(stdlib_unix_poll_linux_srcs) $(stdlib_rt) $(stdlib_rt_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_time_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/unix/poll
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nunix::poll \
-t$(HARECACHE)/unix/poll/unix_poll.td $(stdlib_unix_poll_linux_srcs)
+# unix::poll (+freebsd)
+stdlib_unix_poll_freebsd_srcs= \
+ $(STDLIB)/unix/poll/+freebsd.ha
+
+$(HARECACHE)/unix/poll/unix_poll-freebsd.ssa: $(stdlib_unix_poll_freebsd_srcs) $(stdlib_rt) $(stdlib_rt_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_time_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/unix/poll
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nunix::poll \
+ -t$(HARECACHE)/unix/poll/unix_poll.td $(stdlib_unix_poll_freebsd_srcs)
+
# unix::resolvconf (+any)
stdlib_unix_resolvconf_any_srcs= \
$(STDLIB)/unix/resolvconf/load.ha
-$(HARECACHE)/unix/resolvconf/unix_resolvconf-any.ssa: $(stdlib_unix_resolvconf_any_srcs) $(stdlib_rt) $(stdlib_os) $(stdlib_io) $(stdlib_bufio) $(stdlib_net_ip) $(stdlib_strings)
+$(HARECACHE)/unix/resolvconf/unix_resolvconf-any.ssa: $(stdlib_unix_resolvconf_any_srcs) $(stdlib_rt) $(stdlib_os_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_bufio_$(PLATFORM)) $(stdlib_net_ip_$(PLATFORM)) $(stdlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/unix/resolvconf
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nunix::resolvconf \
@@ -1226,17 +1592,30 @@ stdlib_unix_tty_linux_srcs= \
$(STDLIB)/unix/tty/+linux/open.ha \
$(STDLIB)/unix/tty/+linux/winsize.ha
-$(HARECACHE)/unix/tty/unix_tty-linux.ssa: $(stdlib_unix_tty_linux_srcs) $(stdlib_rt) $(stdlib_rt) $(stdlib_fs) $(stdlib_io) $(stdlib_os)
+$(HARECACHE)/unix/tty/unix_tty-linux.ssa: $(stdlib_unix_tty_linux_srcs) $(stdlib_rt) $(stdlib_rt_$(PLATFORM)) $(stdlib_fs_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_os_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/unix/tty
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nunix::tty \
-t$(HARECACHE)/unix/tty/unix_tty.td $(stdlib_unix_tty_linux_srcs)
+# unix::tty (+freebsd)
+stdlib_unix_tty_freebsd_srcs= \
+ $(STDLIB)/unix/tty/types.ha \
+ $(STDLIB)/unix/tty/+freebsd/isatty.ha \
+ $(STDLIB)/unix/tty/+freebsd/open.ha \
+ $(STDLIB)/unix/tty/+freebsd/winsize.ha
+
+$(HARECACHE)/unix/tty/unix_tty-freebsd.ssa: $(stdlib_unix_tty_freebsd_srcs) $(stdlib_rt) $(stdlib_rt_$(PLATFORM)) $(stdlib_fs_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_os_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/unix/tty
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nunix::tty \
+ -t$(HARECACHE)/unix/tty/unix_tty.td $(stdlib_unix_tty_freebsd_srcs)
+
# uuid (+any)
stdlib_uuid_any_srcs= \
$(STDLIB)/uuid/uuid.ha
-$(HARECACHE)/uuid/uuid-any.ssa: $(stdlib_uuid_any_srcs) $(stdlib_rt) $(stdlib_crypto_random) $(stdlib_strio) $(stdlib_fmt) $(stdlib_endian) $(stdlib_io) $(stdlib_bytes) $(stdlib_bufio) $(stdlib_strings) $(stdlib_strconv)
+$(HARECACHE)/uuid/uuid-any.ssa: $(stdlib_uuid_any_srcs) $(stdlib_rt) $(stdlib_crypto_random_$(PLATFORM)) $(stdlib_strio_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM)) $(stdlib_endian_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) $(stdlib_bufio_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_strconv_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/uuid
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nuuid \
@@ -1275,12 +1654,48 @@ testlib_rt_linux_srcs= \
$(STDLIB)/rt/+test/run.ha \
$(STDLIB)/rt/+test/ztos.ha
+# rt (+freebsd)
+testlib_rt_freebsd_srcs= \
+ $(STDLIB)/rt/+freebsd/abort.ha \
+ $(STDLIB)/rt/+freebsd/env.ha \
+ $(STDLIB)/rt/+freebsd/errno.ha \
+ $(STDLIB)/rt/+freebsd/platformstart.ha \
+ $(STDLIB)/rt/+freebsd/segmalloc.ha \
+ $(STDLIB)/rt/+freebsd/signal.ha \
+ $(STDLIB)/rt/+freebsd/socket.ha \
+ $(STDLIB)/rt/+freebsd/syscallno.ha \
+ $(STDLIB)/rt/+freebsd/syscalls.ha \
+ $(STDLIB)/rt/+freebsd/types.ha \
+ $(STDLIB)/rt/+$(ARCH)/jmp.ha \
+ $(STDLIB)/rt/+$(ARCH)/backtrace.ha \
+ $(STDLIB)/rt/types_arch+$(ARCH).ha \
+ $(STDLIB)/rt/ensure.ha \
+ $(STDLIB)/rt/jmp.ha \
+ $(STDLIB)/rt/malloc.ha \
+ $(STDLIB)/rt/memcpy.ha \
+ $(STDLIB)/rt/memmove.ha \
+ $(STDLIB)/rt/memset.ha \
+ $(STDLIB)/rt/strcmp.ha \
+ $(STDLIB)/rt/types.ha \
+ $(STDLIB)/rt/start+test.ha \
+ $(STDLIB)/rt/abort+test.ha \
+ $(STDLIB)/rt/+test/+$(PLATFORM).ha \
+ $(STDLIB)/rt/+test/cstring.ha \
+ $(STDLIB)/rt/+test/run.ha \
+ $(STDLIB)/rt/+test/ztos.ha
+
$(TESTCACHE)/rt/rt-linux.ssa: $(testlib_rt_linux_srcs) $(testlib_rt)
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/rt
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nrt \
-t$(TESTCACHE)/rt/rt.td $(testlib_rt_linux_srcs)
+$(TESTCACHE)/rt/rt-freebsd.ssa: $(testlib_rt_freebsd_srcs) $(testlib_rt)
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/rt
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nrt \
+ -t$(TESTCACHE)/rt/rt.td $(testlib_rt_freebsd_srcs)
+
$(TESTCACHE)/rt/start.o: $(STDLIB)/rt/+$(PLATFORM)/start+$(ARCH).s
@printf 'AS \t$@\n'
@mkdir -p $(TESTCACHE)/rt
@@ -1322,303 +1737,471 @@ $(TESTCACHE)/rt/rt-linux.a: $(TESTCACHE)/rt/rt-linux.o $(testlib_asm)
@printf 'AR\t$@\n'
@$(AR) -csr $@ $(TESTCACHE)/rt/rt-linux.o $(testlib_asm)
+$(TESTCACHE)/rt/rt-freebsd.a: $(TESTCACHE)/rt/rt-freebsd.o $(testlib_asm)
+ @printf 'AR\t$@\n'
+ @$(AR) -csr $@ $(TESTCACHE)/rt/rt-freebsd.o $(testlib_asm)
+
testlib_rt=$(TESTCACHE)/rt/rt-$(PLATFORM).a
-hare_testlib_deps+=$(testlib_rt)
+testlib_deps_linux+=$(testlib_rt)
+testlib_deps_freebsd+=$(testlib_rt)
+testlib_deps_any+=$(testlib_rt)
# gen_lib ascii (any)
-testlib_ascii=$(TESTCACHE)/ascii/ascii-any.o
-hare_testlib_deps+=$(testlib_ascii)
+testlib_ascii_any=$(TESTCACHE)/ascii/ascii-any.o
+testlib_deps_any+=$(testlib_ascii_any)
+testlib_ascii_linux=$(testlib_ascii_any)
+testlib_ascii_freebsd=$(testlib_ascii_any)
# gen_lib bufio (any)
-testlib_bufio=$(TESTCACHE)/bufio/bufio-any.o
-hare_testlib_deps+=$(testlib_bufio)
+testlib_bufio_any=$(TESTCACHE)/bufio/bufio-any.o
+testlib_deps_any+=$(testlib_bufio_any)
+testlib_bufio_linux=$(testlib_bufio_any)
+testlib_bufio_freebsd=$(testlib_bufio_any)
# gen_lib bytes (any)
-testlib_bytes=$(TESTCACHE)/bytes/bytes-any.o
-hare_testlib_deps+=$(testlib_bytes)
+testlib_bytes_any=$(TESTCACHE)/bytes/bytes-any.o
+testlib_deps_any+=$(testlib_bytes_any)
+testlib_bytes_linux=$(testlib_bytes_any)
+testlib_bytes_freebsd=$(testlib_bytes_any)
# gen_lib compress::flate (any)
-testlib_compress_flate=$(TESTCACHE)/compress/flate/compress_flate-any.o
-hare_testlib_deps+=$(testlib_compress_flate)
+testlib_compress_flate_any=$(TESTCACHE)/compress/flate/compress_flate-any.o
+testlib_deps_any+=$(testlib_compress_flate_any)
+testlib_compress_flate_linux=$(testlib_compress_flate_any)
+testlib_compress_flate_freebsd=$(testlib_compress_flate_any)
# gen_lib compress::zlib (any)
-testlib_compress_zlib=$(TESTCACHE)/compress/zlib/compress_zlib-any.o
-hare_testlib_deps+=$(testlib_compress_zlib)
+testlib_compress_zlib_any=$(TESTCACHE)/compress/zlib/compress_zlib-any.o
+testlib_deps_any+=$(testlib_compress_zlib_any)
+testlib_compress_zlib_linux=$(testlib_compress_zlib_any)
+testlib_compress_zlib_freebsd=$(testlib_compress_zlib_any)
# gen_lib crypto::blake2b (any)
-testlib_crypto_blake2b=$(TESTCACHE)/crypto/blake2b/crypto_blake2b-any.o
-hare_testlib_deps+=$(testlib_crypto_blake2b)
+testlib_crypto_blake2b_any=$(TESTCACHE)/crypto/blake2b/crypto_blake2b-any.o
+testlib_deps_any+=$(testlib_crypto_blake2b_any)
+testlib_crypto_blake2b_linux=$(testlib_crypto_blake2b_any)
+testlib_crypto_blake2b_freebsd=$(testlib_crypto_blake2b_any)
# gen_lib crypto::math (any)
-testlib_crypto_math=$(TESTCACHE)/crypto/math/crypto_math-any.o
-hare_testlib_deps+=$(testlib_crypto_math)
+testlib_crypto_math_any=$(TESTCACHE)/crypto/math/crypto_math-any.o
+testlib_deps_any+=$(testlib_crypto_math_any)
+testlib_crypto_math_linux=$(testlib_crypto_math_any)
+testlib_crypto_math_freebsd=$(testlib_crypto_math_any)
# gen_lib crypto::random (linux)
-testlib_crypto_random=$(TESTCACHE)/crypto/random/crypto_random-linux.o
-hare_testlib_deps+=$(testlib_crypto_random)
+testlib_crypto_random_linux=$(TESTCACHE)/crypto/random/crypto_random-linux.o
+testlib_deps_linux+=$(testlib_crypto_random_linux)
+
+# gen_lib crypto::random (freebsd)
+testlib_crypto_random_freebsd=$(TESTCACHE)/crypto/random/crypto_random-freebsd.o
+testlib_deps_freebsd+=$(testlib_crypto_random_freebsd)
# gen_lib crypto::md5 (any)
-testlib_crypto_md5=$(TESTCACHE)/crypto/md5/crypto_md5-any.o
-hare_testlib_deps+=$(testlib_crypto_md5)
+testlib_crypto_md5_any=$(TESTCACHE)/crypto/md5/crypto_md5-any.o
+testlib_deps_any+=$(testlib_crypto_md5_any)
+testlib_crypto_md5_linux=$(testlib_crypto_md5_any)
+testlib_crypto_md5_freebsd=$(testlib_crypto_md5_any)
# gen_lib crypto::sha1 (any)
-testlib_crypto_sha1=$(TESTCACHE)/crypto/sha1/crypto_sha1-any.o
-hare_testlib_deps+=$(testlib_crypto_sha1)
+testlib_crypto_sha1_any=$(TESTCACHE)/crypto/sha1/crypto_sha1-any.o
+testlib_deps_any+=$(testlib_crypto_sha1_any)
+testlib_crypto_sha1_linux=$(testlib_crypto_sha1_any)
+testlib_crypto_sha1_freebsd=$(testlib_crypto_sha1_any)
# gen_lib crypto::sha256 (any)
-testlib_crypto_sha256=$(TESTCACHE)/crypto/sha256/crypto_sha256-any.o
-hare_testlib_deps+=$(testlib_crypto_sha256)
+testlib_crypto_sha256_any=$(TESTCACHE)/crypto/sha256/crypto_sha256-any.o
+testlib_deps_any+=$(testlib_crypto_sha256_any)
+testlib_crypto_sha256_linux=$(testlib_crypto_sha256_any)
+testlib_crypto_sha256_freebsd=$(testlib_crypto_sha256_any)
# gen_lib crypto::sha512 (any)
-testlib_crypto_sha512=$(TESTCACHE)/crypto/sha512/crypto_sha512-any.o
-hare_testlib_deps+=$(testlib_crypto_sha512)
+testlib_crypto_sha512_any=$(TESTCACHE)/crypto/sha512/crypto_sha512-any.o
+testlib_deps_any+=$(testlib_crypto_sha512_any)
+testlib_crypto_sha512_linux=$(testlib_crypto_sha512_any)
+testlib_crypto_sha512_freebsd=$(testlib_crypto_sha512_any)
# gen_lib dirs (any)
-testlib_dirs=$(TESTCACHE)/dirs/dirs-any.o
-hare_testlib_deps+=$(testlib_dirs)
+testlib_dirs_any=$(TESTCACHE)/dirs/dirs-any.o
+testlib_deps_any+=$(testlib_dirs_any)
+testlib_dirs_linux=$(testlib_dirs_any)
+testlib_dirs_freebsd=$(testlib_dirs_any)
# gen_lib encoding::base64 (any)
-testlib_encoding_base64=$(TESTCACHE)/encoding/base64/encoding_base64-any.o
-hare_testlib_deps+=$(testlib_encoding_base64)
+testlib_encoding_base64_any=$(TESTCACHE)/encoding/base64/encoding_base64-any.o
+testlib_deps_any+=$(testlib_encoding_base64_any)
+testlib_encoding_base64_linux=$(testlib_encoding_base64_any)
+testlib_encoding_base64_freebsd=$(testlib_encoding_base64_any)
# gen_lib encoding::hex (any)
-testlib_encoding_hex=$(TESTCACHE)/encoding/hex/encoding_hex-any.o
-hare_testlib_deps+=$(testlib_encoding_hex)
+testlib_encoding_hex_any=$(TESTCACHE)/encoding/hex/encoding_hex-any.o
+testlib_deps_any+=$(testlib_encoding_hex_any)
+testlib_encoding_hex_linux=$(testlib_encoding_hex_any)
+testlib_encoding_hex_freebsd=$(testlib_encoding_hex_any)
# gen_lib encoding::utf8 (any)
-testlib_encoding_utf8=$(TESTCACHE)/encoding/utf8/encoding_utf8-any.o
-hare_testlib_deps+=$(testlib_encoding_utf8)
+testlib_encoding_utf8_any=$(TESTCACHE)/encoding/utf8/encoding_utf8-any.o
+testlib_deps_any+=$(testlib_encoding_utf8_any)
+testlib_encoding_utf8_linux=$(testlib_encoding_utf8_any)
+testlib_encoding_utf8_freebsd=$(testlib_encoding_utf8_any)
# gen_lib endian (any)
-testlib_endian=$(TESTCACHE)/endian/endian-any.o
-hare_testlib_deps+=$(testlib_endian)
+testlib_endian_any=$(TESTCACHE)/endian/endian-any.o
+testlib_deps_any+=$(testlib_endian_any)
+testlib_endian_linux=$(testlib_endian_any)
+testlib_endian_freebsd=$(testlib_endian_any)
# gen_lib errors (any)
-testlib_errors=$(TESTCACHE)/errors/errors-any.o
-hare_testlib_deps+=$(testlib_errors)
+testlib_errors_any=$(TESTCACHE)/errors/errors-any.o
+testlib_deps_any+=$(testlib_errors_any)
+testlib_errors_linux=$(testlib_errors_any)
+testlib_errors_freebsd=$(testlib_errors_any)
# gen_lib fmt (any)
-testlib_fmt=$(TESTCACHE)/fmt/fmt-any.o
-hare_testlib_deps+=$(testlib_fmt)
+testlib_fmt_any=$(TESTCACHE)/fmt/fmt-any.o
+testlib_deps_any+=$(testlib_fmt_any)
+testlib_fmt_linux=$(testlib_fmt_any)
+testlib_fmt_freebsd=$(testlib_fmt_any)
# gen_lib fnmatch (any)
-testlib_fnmatch=$(TESTCACHE)/fnmatch/fnmatch-any.o
-hare_testlib_deps+=$(testlib_fnmatch)
+testlib_fnmatch_any=$(TESTCACHE)/fnmatch/fnmatch-any.o
+testlib_deps_any+=$(testlib_fnmatch_any)
+testlib_fnmatch_linux=$(testlib_fnmatch_any)
+testlib_fnmatch_freebsd=$(testlib_fnmatch_any)
# gen_lib format::elf (any)
-testlib_format_elf=$(TESTCACHE)/format/elf/format_elf-any.o
-hare_testlib_deps+=$(testlib_format_elf)
+testlib_format_elf_any=$(TESTCACHE)/format/elf/format_elf-any.o
+testlib_deps_any+=$(testlib_format_elf_any)
+testlib_format_elf_linux=$(testlib_format_elf_any)
+testlib_format_elf_freebsd=$(testlib_format_elf_any)
# gen_lib format::ini (any)
-testlib_format_ini=$(TESTCACHE)/format/ini/format_ini-any.o
-hare_testlib_deps+=$(testlib_format_ini)
+testlib_format_ini_any=$(TESTCACHE)/format/ini/format_ini-any.o
+testlib_deps_any+=$(testlib_format_ini_any)
+testlib_format_ini_linux=$(testlib_format_ini_any)
+testlib_format_ini_freebsd=$(testlib_format_ini_any)
# gen_lib format::xml (any)
-testlib_format_xml=$(TESTCACHE)/format/xml/format_xml-any.o
-hare_testlib_deps+=$(testlib_format_xml)
+testlib_format_xml_any=$(TESTCACHE)/format/xml/format_xml-any.o
+testlib_deps_any+=$(testlib_format_xml_any)
+testlib_format_xml_linux=$(testlib_format_xml_any)
+testlib_format_xml_freebsd=$(testlib_format_xml_any)
# gen_lib fs (any)
-testlib_fs=$(TESTCACHE)/fs/fs-any.o
-hare_testlib_deps+=$(testlib_fs)
+testlib_fs_any=$(TESTCACHE)/fs/fs-any.o
+testlib_deps_any+=$(testlib_fs_any)
+testlib_fs_linux=$(testlib_fs_any)
+testlib_fs_freebsd=$(testlib_fs_any)
# gen_lib fs::mem (any)
-testlib_fs_mem=$(TESTCACHE)/fs/mem/fs_mem-any.o
-hare_testlib_deps+=$(testlib_fs_mem)
+testlib_fs_mem_any=$(TESTCACHE)/fs/mem/fs_mem-any.o
+testlib_deps_any+=$(testlib_fs_mem_any)
+testlib_fs_mem_linux=$(testlib_fs_mem_any)
+testlib_fs_mem_freebsd=$(testlib_fs_mem_any)
# gen_lib getopt (any)
-testlib_getopt=$(TESTCACHE)/getopt/getopt-any.o
-hare_testlib_deps+=$(testlib_getopt)
+testlib_getopt_any=$(TESTCACHE)/getopt/getopt-any.o
+testlib_deps_any+=$(testlib_getopt_any)
+testlib_getopt_linux=$(testlib_getopt_any)
+testlib_getopt_freebsd=$(testlib_getopt_any)
# gen_lib hare::ast (any)
-testlib_hare_ast=$(TESTCACHE)/hare/ast/hare_ast-any.o
-hare_testlib_deps+=$(testlib_hare_ast)
+testlib_hare_ast_any=$(TESTCACHE)/hare/ast/hare_ast-any.o
+testlib_deps_any+=$(testlib_hare_ast_any)
+testlib_hare_ast_linux=$(testlib_hare_ast_any)
+testlib_hare_ast_freebsd=$(testlib_hare_ast_any)
# gen_lib hare::lex (any)
-testlib_hare_lex=$(TESTCACHE)/hare/lex/hare_lex-any.o
-hare_testlib_deps+=$(testlib_hare_lex)
+testlib_hare_lex_any=$(TESTCACHE)/hare/lex/hare_lex-any.o
+testlib_deps_any+=$(testlib_hare_lex_any)
+testlib_hare_lex_linux=$(testlib_hare_lex_any)
+testlib_hare_lex_freebsd=$(testlib_hare_lex_any)
# gen_lib hare::module (any)
-testlib_hare_module=$(TESTCACHE)/hare/module/hare_module-any.o
-hare_testlib_deps+=$(testlib_hare_module)
+testlib_hare_module_any=$(TESTCACHE)/hare/module/hare_module-any.o
+testlib_deps_any+=$(testlib_hare_module_any)
+testlib_hare_module_linux=$(testlib_hare_module_any)
+testlib_hare_module_freebsd=$(testlib_hare_module_any)
# gen_lib hare::parse (any)
-testlib_hare_parse=$(TESTCACHE)/hare/parse/hare_parse-any.o
-hare_testlib_deps+=$(testlib_hare_parse)
+testlib_hare_parse_any=$(TESTCACHE)/hare/parse/hare_parse-any.o
+testlib_deps_any+=$(testlib_hare_parse_any)
+testlib_hare_parse_linux=$(testlib_hare_parse_any)
+testlib_hare_parse_freebsd=$(testlib_hare_parse_any)
# gen_lib hare::types (any)
-testlib_hare_types=$(TESTCACHE)/hare/types/hare_types-any.o
-hare_testlib_deps+=$(testlib_hare_types)
+testlib_hare_types_any=$(TESTCACHE)/hare/types/hare_types-any.o
+testlib_deps_any+=$(testlib_hare_types_any)
+testlib_hare_types_linux=$(testlib_hare_types_any)
+testlib_hare_types_freebsd=$(testlib_hare_types_any)
# gen_lib hare::unit (any)
-testlib_hare_unit=$(TESTCACHE)/hare/unit/hare_unit-any.o
-hare_testlib_deps+=$(testlib_hare_unit)
+testlib_hare_unit_any=$(TESTCACHE)/hare/unit/hare_unit-any.o
+testlib_deps_any+=$(testlib_hare_unit_any)
+testlib_hare_unit_linux=$(testlib_hare_unit_any)
+testlib_hare_unit_freebsd=$(testlib_hare_unit_any)
# gen_lib hare::unparse (any)
-testlib_hare_unparse=$(TESTCACHE)/hare/unparse/hare_unparse-any.o
-hare_testlib_deps+=$(testlib_hare_unparse)
+testlib_hare_unparse_any=$(TESTCACHE)/hare/unparse/hare_unparse-any.o
+testlib_deps_any+=$(testlib_hare_unparse_any)
+testlib_hare_unparse_linux=$(testlib_hare_unparse_any)
+testlib_hare_unparse_freebsd=$(testlib_hare_unparse_any)
# gen_lib hash (any)
-testlib_hash=$(TESTCACHE)/hash/hash-any.o
-hare_testlib_deps+=$(testlib_hash)
+testlib_hash_any=$(TESTCACHE)/hash/hash-any.o
+testlib_deps_any+=$(testlib_hash_any)
+testlib_hash_linux=$(testlib_hash_any)
+testlib_hash_freebsd=$(testlib_hash_any)
# gen_lib hash::adler32 (any)
-testlib_hash_adler32=$(TESTCACHE)/hash/adler32/hash_adler32-any.o
-hare_testlib_deps+=$(testlib_hash_adler32)
+testlib_hash_adler32_any=$(TESTCACHE)/hash/adler32/hash_adler32-any.o
+testlib_deps_any+=$(testlib_hash_adler32_any)
+testlib_hash_adler32_linux=$(testlib_hash_adler32_any)
+testlib_hash_adler32_freebsd=$(testlib_hash_adler32_any)
# gen_lib hash::crc16 (any)
-testlib_hash_crc16=$(TESTCACHE)/hash/crc16/hash_crc16-any.o
-hare_testlib_deps+=$(testlib_hash_crc16)
+testlib_hash_crc16_any=$(TESTCACHE)/hash/crc16/hash_crc16-any.o
+testlib_deps_any+=$(testlib_hash_crc16_any)
+testlib_hash_crc16_linux=$(testlib_hash_crc16_any)
+testlib_hash_crc16_freebsd=$(testlib_hash_crc16_any)
# gen_lib hash::crc32 (any)
-testlib_hash_crc32=$(TESTCACHE)/hash/crc32/hash_crc32-any.o
-hare_testlib_deps+=$(testlib_hash_crc32)
+testlib_hash_crc32_any=$(TESTCACHE)/hash/crc32/hash_crc32-any.o
+testlib_deps_any+=$(testlib_hash_crc32_any)
+testlib_hash_crc32_linux=$(testlib_hash_crc32_any)
+testlib_hash_crc32_freebsd=$(testlib_hash_crc32_any)
# gen_lib hash::crc64 (any)
-testlib_hash_crc64=$(TESTCACHE)/hash/crc64/hash_crc64-any.o
-hare_testlib_deps+=$(testlib_hash_crc64)
+testlib_hash_crc64_any=$(TESTCACHE)/hash/crc64/hash_crc64-any.o
+testlib_deps_any+=$(testlib_hash_crc64_any)
+testlib_hash_crc64_linux=$(testlib_hash_crc64_any)
+testlib_hash_crc64_freebsd=$(testlib_hash_crc64_any)
# gen_lib hash::fnv (any)
-testlib_hash_fnv=$(TESTCACHE)/hash/fnv/hash_fnv-any.o
-hare_testlib_deps+=$(testlib_hash_fnv)
+testlib_hash_fnv_any=$(TESTCACHE)/hash/fnv/hash_fnv-any.o
+testlib_deps_any+=$(testlib_hash_fnv_any)
+testlib_hash_fnv_linux=$(testlib_hash_fnv_any)
+testlib_hash_fnv_freebsd=$(testlib_hash_fnv_any)
# gen_lib io (linux)
-testlib_io=$(TESTCACHE)/io/io-linux.o
-hare_testlib_deps+=$(testlib_io)
+testlib_io_linux=$(TESTCACHE)/io/io-linux.o
+testlib_deps_linux+=$(testlib_io_linux)
+
+# gen_lib io (freebsd)
+testlib_io_freebsd=$(TESTCACHE)/io/io-freebsd.o
+testlib_deps_freebsd+=$(testlib_io_freebsd)
# gen_lib iobus::io_uring (linux)
-testlib_iobus_io_uring=$(TESTCACHE)/iobus/io_uring/iobus_io_uring-linux.o
-hare_testlib_deps+=$(testlib_iobus_io_uring)
+testlib_iobus_io_uring_linux=$(TESTCACHE)/iobus/io_uring/iobus_io_uring-linux.o
+testlib_deps_linux+=$(testlib_iobus_io_uring_linux)
# gen_lib linux (linux)
-testlib_linux=$(TESTCACHE)/linux/linux-linux.o
-hare_testlib_deps+=$(testlib_linux)
+testlib_linux_linux=$(TESTCACHE)/linux/linux-linux.o
+testlib_deps_linux+=$(testlib_linux_linux)
# gen_lib linux::signalfd (linux)
-testlib_linux_signalfd=$(TESTCACHE)/linux/signalfd/linux_signalfd-linux.o
-hare_testlib_deps+=$(testlib_linux_signalfd)
+testlib_linux_signalfd_linux=$(TESTCACHE)/linux/signalfd/linux_signalfd-linux.o
+testlib_deps_linux+=$(testlib_linux_signalfd_linux)
# gen_lib linux::io_uring (linux)
-testlib_linux_io_uring=$(TESTCACHE)/linux/io_uring/linux_io_uring-linux.o
-hare_testlib_deps+=$(testlib_linux_io_uring)
+testlib_linux_io_uring_linux=$(TESTCACHE)/linux/io_uring/linux_io_uring-linux.o
+testlib_deps_linux+=$(testlib_linux_io_uring_linux)
# gen_lib linux::vdso (linux)
-testlib_linux_vdso=$(TESTCACHE)/linux/vdso/linux_vdso-linux.o
-hare_testlib_deps+=$(testlib_linux_vdso)
+testlib_linux_vdso_linux=$(TESTCACHE)/linux/vdso/linux_vdso-linux.o
+testlib_deps_linux+=$(testlib_linux_vdso_linux)
# gen_lib math (any)
-testlib_math=$(TESTCACHE)/math/math-any.o
-hare_testlib_deps+=$(testlib_math)
+testlib_math_any=$(TESTCACHE)/math/math-any.o
+testlib_deps_any+=$(testlib_math_any)
+testlib_math_linux=$(testlib_math_any)
+testlib_math_freebsd=$(testlib_math_any)
# gen_lib net (linux)
-testlib_net=$(TESTCACHE)/net/net-linux.o
-hare_testlib_deps+=$(testlib_net)
+testlib_net_linux=$(TESTCACHE)/net/net-linux.o
+testlib_deps_linux+=$(testlib_net_linux)
+
+# gen_lib net (freebsd)
+testlib_net_freebsd=$(TESTCACHE)/net/net-freebsd.o
+testlib_deps_freebsd+=$(testlib_net_freebsd)
# gen_lib net::dial (any)
-testlib_net_dial=$(TESTCACHE)/net/dial/net_dial-any.o
-hare_testlib_deps+=$(testlib_net_dial)
+testlib_net_dial_any=$(TESTCACHE)/net/dial/net_dial-any.o
+testlib_deps_any+=$(testlib_net_dial_any)
+testlib_net_dial_linux=$(testlib_net_dial_any)
+testlib_net_dial_freebsd=$(testlib_net_dial_any)
# gen_lib net::dns (any)
-testlib_net_dns=$(TESTCACHE)/net/dns/net_dns-any.o
-hare_testlib_deps+=$(testlib_net_dns)
+testlib_net_dns_any=$(TESTCACHE)/net/dns/net_dns-any.o
+testlib_deps_any+=$(testlib_net_dns_any)
+testlib_net_dns_linux=$(testlib_net_dns_any)
+testlib_net_dns_freebsd=$(testlib_net_dns_any)
# gen_lib net::ip (linux)
-testlib_net_ip=$(TESTCACHE)/net/ip/net_ip-linux.o
-hare_testlib_deps+=$(testlib_net_ip)
+testlib_net_ip_linux=$(TESTCACHE)/net/ip/net_ip-linux.o
+testlib_deps_linux+=$(testlib_net_ip_linux)
+
+# gen_lib net::ip (freebsd)
+testlib_net_ip_freebsd=$(TESTCACHE)/net/ip/net_ip-freebsd.o
+testlib_deps_freebsd+=$(testlib_net_ip_freebsd)
# gen_lib net::tcp (linux)
-testlib_net_tcp=$(TESTCACHE)/net/tcp/net_tcp-linux.o
-hare_testlib_deps+=$(testlib_net_tcp)
+testlib_net_tcp_linux=$(TESTCACHE)/net/tcp/net_tcp-linux.o
+testlib_deps_linux+=$(testlib_net_tcp_linux)
+
+# gen_lib net::tcp (freebsd)
+testlib_net_tcp_freebsd=$(TESTCACHE)/net/tcp/net_tcp-freebsd.o
+testlib_deps_freebsd+=$(testlib_net_tcp_freebsd)
# gen_lib net::udp (linux)
-testlib_net_udp=$(TESTCACHE)/net/udp/net_udp-linux.o
-hare_testlib_deps+=$(testlib_net_udp)
+testlib_net_udp_linux=$(TESTCACHE)/net/udp/net_udp-linux.o
+testlib_deps_linux+=$(testlib_net_udp_linux)
+
+# gen_lib net::udp (freebsd)
+testlib_net_udp_freebsd=$(TESTCACHE)/net/udp/net_udp-freebsd.o
+testlib_deps_freebsd+=$(testlib_net_udp_freebsd)
# gen_lib net::unix (linux)
-testlib_net_unix=$(TESTCACHE)/net/unix/net_unix-linux.o
-hare_testlib_deps+=$(testlib_net_unix)
+testlib_net_unix_linux=$(TESTCACHE)/net/unix/net_unix-linux.o
+testlib_deps_linux+=$(testlib_net_unix_linux)
+
+# gen_lib net::unix (freebsd)
+testlib_net_unix_freebsd=$(TESTCACHE)/net/unix/net_unix-freebsd.o
+testlib_deps_freebsd+=$(testlib_net_unix_freebsd)
# gen_lib math::random (any)
-testlib_math_random=$(TESTCACHE)/math/random/math_random-any.o
-hare_testlib_deps+=$(testlib_math_random)
+testlib_math_random_any=$(TESTCACHE)/math/random/math_random-any.o
+testlib_deps_any+=$(testlib_math_random_any)
+testlib_math_random_linux=$(testlib_math_random_any)
+testlib_math_random_freebsd=$(testlib_math_random_any)
# gen_lib os (linux)
-testlib_os=$(TESTCACHE)/os/os-linux.o
-hare_testlib_deps+=$(testlib_os)
+testlib_os_linux=$(TESTCACHE)/os/os-linux.o
+testlib_deps_linux+=$(testlib_os_linux)
+
+# gen_lib os (freebsd)
+testlib_os_freebsd=$(TESTCACHE)/os/os-freebsd.o
+testlib_deps_freebsd+=$(testlib_os_freebsd)
# gen_lib os::exec (linux)
-testlib_os_exec=$(TESTCACHE)/os/exec/os_exec-linux.o
-hare_testlib_deps+=$(testlib_os_exec)
+testlib_os_exec_linux=$(TESTCACHE)/os/exec/os_exec-linux.o
+testlib_deps_linux+=$(testlib_os_exec_linux)
+
+# gen_lib os::exec (freebsd)
+testlib_os_exec_freebsd=$(TESTCACHE)/os/exec/os_exec-freebsd.o
+testlib_deps_freebsd+=$(testlib_os_exec_freebsd)
# gen_lib path (any)
-testlib_path=$(TESTCACHE)/path/path-any.o
-hare_testlib_deps+=$(testlib_path)
+testlib_path_any=$(TESTCACHE)/path/path-any.o
+testlib_deps_any+=$(testlib_path_any)
+testlib_path_linux=$(testlib_path_any)
+testlib_path_freebsd=$(testlib_path_any)
# gen_lib slice (any)
-testlib_slice=$(TESTCACHE)/slice/slice-any.o
-hare_testlib_deps+=$(testlib_slice)
+testlib_slice_any=$(TESTCACHE)/slice/slice-any.o
+testlib_deps_any+=$(testlib_slice_any)
+testlib_slice_linux=$(testlib_slice_any)
+testlib_slice_freebsd=$(testlib_slice_any)
# gen_lib sort (any)
-testlib_sort=$(TESTCACHE)/sort/sort-any.o
-hare_testlib_deps+=$(testlib_sort)
+testlib_sort_any=$(TESTCACHE)/sort/sort-any.o
+testlib_deps_any+=$(testlib_sort_any)
+testlib_sort_linux=$(testlib_sort_any)
+testlib_sort_freebsd=$(testlib_sort_any)
# gen_lib strconv (any)
-testlib_strconv=$(TESTCACHE)/strconv/strconv-any.o
-hare_testlib_deps+=$(testlib_strconv)
+testlib_strconv_any=$(TESTCACHE)/strconv/strconv-any.o
+testlib_deps_any+=$(testlib_strconv_any)
+testlib_strconv_linux=$(testlib_strconv_any)
+testlib_strconv_freebsd=$(testlib_strconv_any)
# gen_lib strings (any)
-testlib_strings=$(TESTCACHE)/strings/strings-any.o
-hare_testlib_deps+=$(testlib_strings)
+testlib_strings_any=$(TESTCACHE)/strings/strings-any.o
+testlib_deps_any+=$(testlib_strings_any)
+testlib_strings_linux=$(testlib_strings_any)
+testlib_strings_freebsd=$(testlib_strings_any)
# gen_lib strio (any)
-testlib_strio=$(TESTCACHE)/strio/strio-any.o
-hare_testlib_deps+=$(testlib_strio)
+testlib_strio_any=$(TESTCACHE)/strio/strio-any.o
+testlib_deps_any+=$(testlib_strio_any)
+testlib_strio_linux=$(testlib_strio_any)
+testlib_strio_freebsd=$(testlib_strio_any)
# gen_lib temp (linux)
-testlib_temp=$(TESTCACHE)/temp/temp-linux.o
-hare_testlib_deps+=$(testlib_temp)
+testlib_temp_linux=$(TESTCACHE)/temp/temp-linux.o
+testlib_deps_linux+=$(testlib_temp_linux)
+
+# gen_lib temp (freebsd)
+testlib_temp_freebsd=$(TESTCACHE)/temp/temp-freebsd.o
+testlib_deps_freebsd+=$(testlib_temp_freebsd)
# gen_lib time (linux)
-testlib_time=$(TESTCACHE)/time/time-linux.o
-hare_testlib_deps+=$(testlib_time)
+testlib_time_linux=$(TESTCACHE)/time/time-linux.o
+testlib_deps_linux+=$(testlib_time_linux)
+
+# gen_lib time (freebsd)
+testlib_time_freebsd=$(TESTCACHE)/time/time-freebsd.o
+testlib_deps_freebsd+=$(testlib_time_freebsd)
# gen_lib types (any)
-testlib_types=$(TESTCACHE)/types/types-any.o
-hare_testlib_deps+=$(testlib_types)
+testlib_types_any=$(TESTCACHE)/types/types-any.o
+testlib_deps_any+=$(testlib_types_any)
+testlib_types_linux=$(testlib_types_any)
+testlib_types_freebsd=$(testlib_types_any)
# gen_lib unix (linux)
-testlib_unix=$(TESTCACHE)/unix/unix-linux.o
-hare_testlib_deps+=$(testlib_unix)
+testlib_unix_linux=$(TESTCACHE)/unix/unix-linux.o
+testlib_deps_linux+=$(testlib_unix_linux)
+
+# gen_lib unix (freebsd)
+testlib_unix_freebsd=$(TESTCACHE)/unix/unix-freebsd.o
+testlib_deps_freebsd+=$(testlib_unix_freebsd)
# gen_lib unix::hosts (any)
-testlib_unix_hosts=$(TESTCACHE)/unix/hosts/unix_hosts-any.o
-hare_testlib_deps+=$(testlib_unix_hosts)
+testlib_unix_hosts_any=$(TESTCACHE)/unix/hosts/unix_hosts-any.o
+testlib_deps_any+=$(testlib_unix_hosts_any)
+testlib_unix_hosts_linux=$(testlib_unix_hosts_any)
+testlib_unix_hosts_freebsd=$(testlib_unix_hosts_any)
# gen_lib unix::passwd (any)
-testlib_unix_passwd=$(TESTCACHE)/unix/passwd/unix_passwd-any.o
-hare_testlib_deps+=$(testlib_unix_passwd)
+testlib_unix_passwd_any=$(TESTCACHE)/unix/passwd/unix_passwd-any.o
+testlib_deps_any+=$(testlib_unix_passwd_any)
+testlib_unix_passwd_linux=$(testlib_unix_passwd_any)
+testlib_unix_passwd_freebsd=$(testlib_unix_passwd_any)
# gen_lib unix::poll (linux)
-testlib_unix_poll=$(TESTCACHE)/unix/poll/unix_poll-linux.o
-hare_testlib_deps+=$(testlib_unix_poll)
+testlib_unix_poll_linux=$(TESTCACHE)/unix/poll/unix_poll-linux.o
+testlib_deps_linux+=$(testlib_unix_poll_linux)
+
+# gen_lib unix::poll (freebsd)
+testlib_unix_poll_freebsd=$(TESTCACHE)/unix/poll/unix_poll-freebsd.o
+testlib_deps_freebsd+=$(testlib_unix_poll_freebsd)
# gen_lib unix::resolvconf (any)
-testlib_unix_resolvconf=$(TESTCACHE)/unix/resolvconf/unix_resolvconf-any.o
-hare_testlib_deps+=$(testlib_unix_resolvconf)
+testlib_unix_resolvconf_any=$(TESTCACHE)/unix/resolvconf/unix_resolvconf-any.o
+testlib_deps_any+=$(testlib_unix_resolvconf_any)
+testlib_unix_resolvconf_linux=$(testlib_unix_resolvconf_any)
+testlib_unix_resolvconf_freebsd=$(testlib_unix_resolvconf_any)
# gen_lib unix::tty (linux)
-testlib_unix_tty=$(TESTCACHE)/unix/tty/unix_tty-linux.o
-hare_testlib_deps+=$(testlib_unix_tty)
+testlib_unix_tty_linux=$(TESTCACHE)/unix/tty/unix_tty-linux.o
+testlib_deps_linux+=$(testlib_unix_tty_linux)
+
+# gen_lib unix::tty (freebsd)
+testlib_unix_tty_freebsd=$(TESTCACHE)/unix/tty/unix_tty-freebsd.o
+testlib_deps_freebsd+=$(testlib_unix_tty_freebsd)
# gen_lib uuid (any)
-testlib_uuid=$(TESTCACHE)/uuid/uuid-any.o
-hare_testlib_deps+=$(testlib_uuid)
+testlib_uuid_any=$(TESTCACHE)/uuid/uuid-any.o
+testlib_deps_any+=$(testlib_uuid_any)
+testlib_uuid_linux=$(testlib_uuid_any)
+testlib_uuid_freebsd=$(testlib_uuid_any)
# ascii (+any)
testlib_ascii_any_srcs= \
$(STDLIB)/ascii/ctype.ha \
$(STDLIB)/ascii/strcmp.ha
-$(TESTCACHE)/ascii/ascii-any.ssa: $(testlib_ascii_any_srcs) $(testlib_rt) $(testlib_strings)
+$(TESTCACHE)/ascii/ascii-any.ssa: $(testlib_ascii_any_srcs) $(testlib_rt) $(testlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/ascii
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nascii \
@@ -1630,7 +2213,7 @@ testlib_bufio_any_srcs= \
$(STDLIB)/bufio/memstream.ha \
$(STDLIB)/bufio/scanner.ha
-$(TESTCACHE)/bufio/bufio-any.ssa: $(testlib_bufio_any_srcs) $(testlib_rt) $(testlib_io) $(testlib_bytes) $(testlib_strings) $(testlib_encoding_utf8) $(testlib_errors) $(testlib_types)
+$(TESTCACHE)/bufio/bufio-any.ssa: $(testlib_bufio_any_srcs) $(testlib_rt) $(testlib_io_$(PLATFORM)) $(testlib_bytes_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_encoding_utf8_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_types_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/bufio
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nbufio \
@@ -1646,7 +2229,7 @@ testlib_bytes_any_srcs= \
$(STDLIB)/bytes/tokenize.ha \
$(STDLIB)/bytes/two_way.ha
-$(TESTCACHE)/bytes/bytes-any.ssa: $(testlib_bytes_any_srcs) $(testlib_rt) $(testlib_types)
+$(TESTCACHE)/bytes/bytes-any.ssa: $(testlib_bytes_any_srcs) $(testlib_rt) $(testlib_types_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/bytes
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nbytes \
@@ -1656,7 +2239,7 @@ $(TESTCACHE)/bytes/bytes-any.ssa: $(testlib_bytes_any_srcs) $(testlib_rt) $(test
testlib_compress_flate_any_srcs= \
$(STDLIB)/compress/flate/inflate.ha
-$(TESTCACHE)/compress/flate/compress_flate-any.ssa: $(testlib_compress_flate_any_srcs) $(testlib_rt) $(testlib_bufio) $(testlib_bytes) $(testlib_endian) $(testlib_errors) $(testlib_io) $(testlib_fmt)
+$(TESTCACHE)/compress/flate/compress_flate-any.ssa: $(testlib_compress_flate_any_srcs) $(testlib_rt) $(testlib_bufio_$(PLATFORM)) $(testlib_bytes_$(PLATFORM)) $(testlib_endian_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_fmt_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/compress/flate
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncompress::flate \
@@ -1667,7 +2250,7 @@ testlib_compress_zlib_any_srcs= \
$(STDLIB)/compress/zlib/data+test.ha \
$(STDLIB)/compress/zlib/reader.ha
-$(TESTCACHE)/compress/zlib/compress_zlib-any.ssa: $(testlib_compress_zlib_any_srcs) $(testlib_rt) $(testlib_bufio) $(testlib_bytes) $(testlib_compress_flate) $(testlib_endian) $(testlib_errors) $(testlib_hash) $(testlib_hash_adler32) $(testlib_io) $(testlib_fmt)
+$(TESTCACHE)/compress/zlib/compress_zlib-any.ssa: $(testlib_compress_zlib_any_srcs) $(testlib_rt) $(testlib_bufio_$(PLATFORM)) $(testlib_bytes_$(PLATFORM)) $(testlib_compress_flate_$(PLATFORM)) $(testlib_endian_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_hash_adler32_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_fmt_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/compress/zlib
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncompress::zlib \
@@ -1679,7 +2262,7 @@ testlib_crypto_blake2b_any_srcs= \
$(STDLIB)/crypto/blake2b/+test.ha \
$(STDLIB)/crypto/blake2b/vectors+test.ha
-$(TESTCACHE)/crypto/blake2b/crypto_blake2b-any.ssa: $(testlib_crypto_blake2b_any_srcs) $(testlib_rt) $(testlib_encoding_hex) $(testlib_fmt) $(testlib_hash) $(testlib_io) $(testlib_strings) $(testlib_strio) $(testlib_crypto_math) $(testlib_endian)
+$(TESTCACHE)/crypto/blake2b/crypto_blake2b-any.ssa: $(testlib_crypto_blake2b_any_srcs) $(testlib_rt) $(testlib_encoding_hex_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_strio_$(PLATFORM)) $(testlib_crypto_math_$(PLATFORM)) $(testlib_endian_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/crypto/blake2b
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncrypto::blake2b \
@@ -1700,18 +2283,29 @@ testlib_crypto_random_linux_srcs= \
$(STDLIB)/crypto/random/+linux.ha \
$(STDLIB)/crypto/random/random.ha
-$(TESTCACHE)/crypto/random/crypto_random-linux.ssa: $(testlib_crypto_random_linux_srcs) $(testlib_rt) $(testlib_rt) $(testlib_io) $(testlib_errors)
+$(TESTCACHE)/crypto/random/crypto_random-linux.ssa: $(testlib_crypto_random_linux_srcs) $(testlib_rt) $(testlib_rt_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_errors_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/crypto/random
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncrypto::random \
-t$(TESTCACHE)/crypto/random/crypto_random.td $(testlib_crypto_random_linux_srcs)
+# crypto::random (+freebsd)
+testlib_crypto_random_freebsd_srcs= \
+ $(STDLIB)/crypto/random/+freebsd.ha \
+ $(STDLIB)/crypto/random/random.ha
+
+$(TESTCACHE)/crypto/random/crypto_random-freebsd.ssa: $(testlib_crypto_random_freebsd_srcs) $(testlib_rt) $(testlib_rt_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_errors_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/crypto/random
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncrypto::random \
+ -t$(TESTCACHE)/crypto/random/crypto_random.td $(testlib_crypto_random_freebsd_srcs)
+
# crypto::md5 (+any)
testlib_crypto_md5_any_srcs= \
$(STDLIB)/crypto/md5/md5.ha \
$(STDLIB)/crypto/md5/+test.ha
-$(TESTCACHE)/crypto/md5/crypto_md5-any.ssa: $(testlib_crypto_md5_any_srcs) $(testlib_rt) $(testlib_hash) $(testlib_io) $(testlib_endian) $(testlib_fmt) $(testlib_strio) $(testlib_strings)
+$(TESTCACHE)/crypto/md5/crypto_md5-any.ssa: $(testlib_crypto_md5_any_srcs) $(testlib_rt) $(testlib_hash_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_endian_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_strio_$(PLATFORM)) $(testlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/crypto/md5
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncrypto::md5 \
@@ -1722,7 +2316,7 @@ testlib_crypto_sha1_any_srcs= \
$(STDLIB)/crypto/sha1/sha1.ha \
$(STDLIB)/crypto/sha1/+test.ha
-$(TESTCACHE)/crypto/sha1/crypto_sha1-any.ssa: $(testlib_crypto_sha1_any_srcs) $(testlib_rt) $(testlib_hash) $(testlib_io) $(testlib_endian) $(testlib_fmt) $(testlib_strio) $(testlib_strings)
+$(TESTCACHE)/crypto/sha1/crypto_sha1-any.ssa: $(testlib_crypto_sha1_any_srcs) $(testlib_rt) $(testlib_hash_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_endian_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_strio_$(PLATFORM)) $(testlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/crypto/sha1
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncrypto::sha1 \
@@ -1733,7 +2327,7 @@ testlib_crypto_sha256_any_srcs= \
$(STDLIB)/crypto/sha256/sha256.ha \
$(STDLIB)/crypto/sha256/+test.ha
-$(TESTCACHE)/crypto/sha256/crypto_sha256-any.ssa: $(testlib_crypto_sha256_any_srcs) $(testlib_rt) $(testlib_hash) $(testlib_io) $(testlib_endian) $(testlib_fmt) $(testlib_strio) $(testlib_strings)
+$(TESTCACHE)/crypto/sha256/crypto_sha256-any.ssa: $(testlib_crypto_sha256_any_srcs) $(testlib_rt) $(testlib_hash_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_endian_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_strio_$(PLATFORM)) $(testlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/crypto/sha256
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncrypto::sha256 \
@@ -1744,7 +2338,7 @@ testlib_crypto_sha512_any_srcs= \
$(STDLIB)/crypto/sha512/sha512.ha \
$(STDLIB)/crypto/sha512/+test.ha
-$(TESTCACHE)/crypto/sha512/crypto_sha512-any.ssa: $(testlib_crypto_sha512_any_srcs) $(testlib_rt) $(testlib_hash) $(testlib_io) $(testlib_endian) $(testlib_fmt) $(testlib_strio) $(testlib_strings)
+$(TESTCACHE)/crypto/sha512/crypto_sha512-any.ssa: $(testlib_crypto_sha512_any_srcs) $(testlib_rt) $(testlib_hash_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_endian_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_strio_$(PLATFORM)) $(testlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/crypto/sha512
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncrypto::sha512 \
@@ -1754,7 +2348,7 @@ $(TESTCACHE)/crypto/sha512/crypto_sha512-any.ssa: $(testlib_crypto_sha512_any_sr
testlib_dirs_any_srcs= \
$(STDLIB)/dirs/xdg.ha
-$(TESTCACHE)/dirs/dirs-any.ssa: $(testlib_dirs_any_srcs) $(testlib_rt) $(testlib_fs) $(testlib_os) $(testlib_path)
+$(TESTCACHE)/dirs/dirs-any.ssa: $(testlib_dirs_any_srcs) $(testlib_rt) $(testlib_fs_$(PLATFORM)) $(testlib_os_$(PLATFORM)) $(testlib_path_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/dirs
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ndirs \
@@ -1764,7 +2358,7 @@ $(TESTCACHE)/dirs/dirs-any.ssa: $(testlib_dirs_any_srcs) $(testlib_rt) $(testlib
testlib_encoding_base64_any_srcs= \
$(STDLIB)/encoding/base64/base64.ha
-$(TESTCACHE)/encoding/base64/encoding_base64-any.ssa: $(testlib_encoding_base64_any_srcs) $(testlib_rt) $(testlib_bufio) $(testlib_bytes) $(testlib_io) $(testlib_strio) $(testlib_strings)
+$(TESTCACHE)/encoding/base64/encoding_base64-any.ssa: $(testlib_encoding_base64_any_srcs) $(testlib_rt) $(testlib_bufio_$(PLATFORM)) $(testlib_bytes_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_strio_$(PLATFORM)) $(testlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/encoding/base64
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nencoding::base64 \
@@ -1774,7 +2368,7 @@ $(TESTCACHE)/encoding/base64/encoding_base64-any.ssa: $(testlib_encoding_base64_
testlib_encoding_hex_any_srcs= \
$(STDLIB)/encoding/hex/hex.ha
-$(TESTCACHE)/encoding/hex/encoding_hex-any.ssa: $(testlib_encoding_hex_any_srcs) $(testlib_rt) $(testlib_ascii) $(testlib_bytes) $(testlib_fmt) $(testlib_io) $(testlib_strconv) $(testlib_strio) $(testlib_strings)
+$(TESTCACHE)/encoding/hex/encoding_hex-any.ssa: $(testlib_encoding_hex_any_srcs) $(testlib_rt) $(testlib_ascii_$(PLATFORM)) $(testlib_bytes_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_strconv_$(PLATFORM)) $(testlib_strio_$(PLATFORM)) $(testlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/encoding/hex
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nencoding::hex \
@@ -1786,7 +2380,7 @@ testlib_encoding_utf8_any_srcs= \
$(STDLIB)/encoding/utf8/encode.ha \
$(STDLIB)/encoding/utf8/rune.ha
-$(TESTCACHE)/encoding/utf8/encoding_utf8-any.ssa: $(testlib_encoding_utf8_any_srcs) $(testlib_rt) $(testlib_types)
+$(TESTCACHE)/encoding/utf8/encoding_utf8-any.ssa: $(testlib_encoding_utf8_any_srcs) $(testlib_rt) $(testlib_types_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/encoding/utf8
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nencoding::utf8 \
@@ -1823,7 +2417,7 @@ $(TESTCACHE)/errors/errors-any.ssa: $(testlib_errors_any_srcs) $(testlib_rt)
testlib_fmt_any_srcs= \
$(STDLIB)/fmt/fmt.ha
-$(TESTCACHE)/fmt/fmt-any.ssa: $(testlib_fmt_any_srcs) $(testlib_rt) $(testlib_bufio) $(testlib_io) $(testlib_os) $(testlib_strconv) $(testlib_strings) $(testlib_types)
+$(TESTCACHE)/fmt/fmt-any.ssa: $(testlib_fmt_any_srcs) $(testlib_rt) $(testlib_bufio_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_os_$(PLATFORM)) $(testlib_strconv_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_types_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/fmt
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nfmt \
@@ -1834,7 +2428,7 @@ testlib_fnmatch_any_srcs= \
$(STDLIB)/fnmatch/fnmatch.ha \
$(STDLIB)/fnmatch/+test.ha
-$(TESTCACHE)/fnmatch/fnmatch-any.ssa: $(testlib_fnmatch_any_srcs) $(testlib_rt) $(testlib_strings) $(testlib_bytes) $(testlib_sort) $(testlib_ascii) $(testlib_io) $(testlib_fmt)
+$(TESTCACHE)/fnmatch/fnmatch-any.ssa: $(testlib_fnmatch_any_srcs) $(testlib_rt) $(testlib_strings_$(PLATFORM)) $(testlib_bytes_$(PLATFORM)) $(testlib_sort_$(PLATFORM)) $(testlib_ascii_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_fmt_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/fnmatch
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nfnmatch \
@@ -1858,7 +2452,7 @@ testlib_format_ini_any_srcs= \
$(STDLIB)/format/ini/types.ha \
$(STDLIB)/format/ini/+test.ha
-$(TESTCACHE)/format/ini/format_ini-any.ssa: $(testlib_format_ini_any_srcs) $(testlib_rt) $(testlib_bufio) $(testlib_encoding_utf8) $(testlib_fmt) $(testlib_io) $(testlib_strings)
+$(TESTCACHE)/format/ini/format_ini-any.ssa: $(testlib_format_ini_any_srcs) $(testlib_rt) $(testlib_bufio_$(PLATFORM)) $(testlib_encoding_utf8_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/format/ini
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nformat::ini \
@@ -1871,7 +2465,7 @@ testlib_format_xml_any_srcs= \
$(STDLIB)/format/xml/chars.ha \
$(STDLIB)/format/xml/+test.ha
-$(TESTCACHE)/format/xml/format_xml-any.ssa: $(testlib_format_xml_any_srcs) $(testlib_rt) $(testlib_io) $(testlib_bufio) $(testlib_strings) $(testlib_ascii) $(testlib_strio) $(testlib_os)
+$(TESTCACHE)/format/xml/format_xml-any.ssa: $(testlib_format_xml_any_srcs) $(testlib_rt) $(testlib_io_$(PLATFORM)) $(testlib_bufio_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_ascii_$(PLATFORM)) $(testlib_strio_$(PLATFORM)) $(testlib_os_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/format/xml
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nformat::xml \
@@ -1883,7 +2477,7 @@ testlib_fs_any_srcs= \
$(STDLIB)/fs/fs.ha \
$(STDLIB)/fs/util.ha
-$(TESTCACHE)/fs/fs-any.ssa: $(testlib_fs_any_srcs) $(testlib_rt) $(testlib_io) $(testlib_strings) $(testlib_path) $(testlib_time) $(testlib_errors)
+$(TESTCACHE)/fs/fs-any.ssa: $(testlib_fs_any_srcs) $(testlib_rt) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_path_$(PLATFORM)) $(testlib_time_$(PLATFORM)) $(testlib_errors_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/fs
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nfs \
@@ -1896,7 +2490,7 @@ testlib_fs_mem_any_srcs= \
$(STDLIB)/fs/mem/util.ha \
$(STDLIB)/fs/mem/+test.ha
-$(TESTCACHE)/fs/mem/fs_mem-any.ssa: $(testlib_fs_mem_any_srcs) $(testlib_rt) $(testlib_bufio) $(testlib_errors) $(testlib_fs) $(testlib_hash) $(testlib_hash_fnv) $(testlib_io) $(testlib_path) $(testlib_strconv) $(testlib_strings) $(testlib_types)
+$(TESTCACHE)/fs/mem/fs_mem-any.ssa: $(testlib_fs_mem_any_srcs) $(testlib_rt) $(testlib_bufio_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_fs_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_hash_fnv_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_path_$(PLATFORM)) $(testlib_strconv_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_types_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/fs/mem
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nfs::mem \
@@ -1906,7 +2500,7 @@ $(TESTCACHE)/fs/mem/fs_mem-any.ssa: $(testlib_fs_mem_any_srcs) $(testlib_rt) $(t
testlib_getopt_any_srcs= \
$(STDLIB)/getopt/getopts.ha
-$(TESTCACHE)/getopt/getopt-any.ssa: $(testlib_getopt_any_srcs) $(testlib_rt) $(testlib_encoding_utf8) $(testlib_fmt) $(testlib_io) $(testlib_os) $(testlib_strings)
+$(TESTCACHE)/getopt/getopt-any.ssa: $(testlib_getopt_any_srcs) $(testlib_rt) $(testlib_encoding_utf8_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_os_$(PLATFORM)) $(testlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/getopt
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ngetopt \
@@ -1921,7 +2515,7 @@ testlib_hare_ast_any_srcs= \
$(STDLIB)/hare/ast/type.ha \
$(STDLIB)/hare/ast/unit.ha
-$(TESTCACHE)/hare/ast/hare_ast-any.ssa: $(testlib_hare_ast_any_srcs) $(testlib_rt) $(testlib_hare_lex) $(testlib_strings)
+$(TESTCACHE)/hare/ast/hare_ast-any.ssa: $(testlib_hare_ast_any_srcs) $(testlib_rt) $(testlib_hare_lex_$(PLATFORM)) $(testlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/hare/ast
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhare::ast \
@@ -1933,7 +2527,7 @@ testlib_hare_lex_any_srcs= \
$(STDLIB)/hare/lex/lex.ha \
$(STDLIB)/hare/lex/+test.ha
-$(TESTCACHE)/hare/lex/hare_lex-any.ssa: $(testlib_hare_lex_any_srcs) $(testlib_rt) $(testlib_io) $(testlib_bufio) $(testlib_strings) $(testlib_types) $(testlib_fmt) $(testlib_sort) $(testlib_strio)
+$(TESTCACHE)/hare/lex/hare_lex-any.ssa: $(testlib_hare_lex_any_srcs) $(testlib_rt) $(testlib_io_$(PLATFORM)) $(testlib_bufio_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_types_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_sort_$(PLATFORM)) $(testlib_strio_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/hare/lex
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhare::lex \
@@ -1946,7 +2540,7 @@ testlib_hare_module_any_srcs= \
$(STDLIB)/hare/module/scan.ha \
$(STDLIB)/hare/module/manifest.ha
-$(TESTCACHE)/hare/module/hare_module-any.ssa: $(testlib_hare_module_any_srcs) $(testlib_rt) $(testlib_hare_ast) $(testlib_hare_lex) $(testlib_hare_parse) $(testlib_hare_unparse) $(testlib_strio) $(testlib_fs) $(testlib_io) $(testlib_strings) $(testlib_hash) $(testlib_crypto_sha256) $(testlib_dirs) $(testlib_bytes) $(testlib_encoding_utf8) $(testlib_ascii) $(testlib_fmt) $(testlib_time) $(testlib_slice) $(testlib_bufio) $(testlib_strconv) $(testlib_os) $(testlib_encoding_hex) $(testlib_sort) $(testlib_errors) $(testlib_temp)
+$(TESTCACHE)/hare/module/hare_module-any.ssa: $(testlib_hare_module_any_srcs) $(testlib_rt) $(testlib_hare_ast_$(PLATFORM)) $(testlib_hare_lex_$(PLATFORM)) $(testlib_hare_parse_$(PLATFORM)) $(testlib_hare_unparse_$(PLATFORM)) $(testlib_strio_$(PLATFORM)) $(testlib_fs_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_crypto_sha256_$(PLATFORM)) $(testlib_dirs_$(PLATFORM)) $(testlib_bytes_$(PLATFORM)) $(testlib_encoding_utf8_$(PLATFORM)) $(testlib_ascii_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_time_$(PLATFORM)) $(testlib_slice_$(PLATFORM)) $(testlib_bufio_$(PLATFORM)) $(testlib_strconv_$(PLATFORM)) $(testlib_os_$(PLATFORM)) $(testlib_encoding_hex_$(PLATFORM)) $(testlib_sort_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_temp_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/hare/module
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhare::module \
@@ -1968,7 +2562,7 @@ testlib_hare_parse_any_srcs= \
$(STDLIB)/hare/parse/+test/types.ha \
$(STDLIB)/hare/parse/+test/unit.ha
-$(TESTCACHE)/hare/parse/hare_parse-any.ssa: $(testlib_hare_parse_any_srcs) $(testlib_rt) $(testlib_bufio) $(testlib_fmt) $(testlib_hare_ast) $(testlib_hare_lex) $(testlib_hare_unparse) $(testlib_io) $(testlib_strings) $(testlib_strio) $(testlib_fmt)
+$(TESTCACHE)/hare/parse/hare_parse-any.ssa: $(testlib_hare_parse_any_srcs) $(testlib_rt) $(testlib_bufio_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_hare_ast_$(PLATFORM)) $(testlib_hare_lex_$(PLATFORM)) $(testlib_hare_unparse_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_strio_$(PLATFORM)) $(testlib_fmt_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/hare/parse
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhare::parse \
@@ -1985,7 +2579,7 @@ testlib_hare_types_any_srcs= \
$(STDLIB)/hare/types/types.ha \
$(STDLIB)/hare/types/+test.ha
-$(TESTCACHE)/hare/types/hare_types-any.ssa: $(testlib_hare_types_any_srcs) $(testlib_rt) $(testlib_hare_ast) $(testlib_hare_parse) $(testlib_hash) $(testlib_hash_fnv) $(testlib_endian)
+$(TESTCACHE)/hare/types/hare_types-any.ssa: $(testlib_hare_types_any_srcs) $(testlib_rt) $(testlib_hare_ast_$(PLATFORM)) $(testlib_hare_parse_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_hash_fnv_$(PLATFORM)) $(testlib_endian_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/hare/types
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhare::types \
@@ -2003,7 +2597,7 @@ testlib_hare_unit_any_srcs= \
$(STDLIB)/hare/unit/unit.ha \
$(STDLIB)/hare/unit/+test.ha
-$(TESTCACHE)/hare/unit/hare_unit-any.ssa: $(testlib_hare_unit_any_srcs) $(testlib_rt) $(testlib_hare_ast) $(testlib_hare_types) $(testlib_hash) $(testlib_hash_fnv) $(testlib_strings) $(testlib_hare_lex) $(testlib_bufio) $(testlib_hare_parse)
+$(TESTCACHE)/hare/unit/hare_unit-any.ssa: $(testlib_hare_unit_any_srcs) $(testlib_rt) $(testlib_hare_ast_$(PLATFORM)) $(testlib_hare_types_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_hash_fnv_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_hare_lex_$(PLATFORM)) $(testlib_bufio_$(PLATFORM)) $(testlib_hare_parse_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/hare/unit
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhare::unit \
@@ -2019,7 +2613,7 @@ testlib_hare_unparse_any_srcs= \
$(STDLIB)/hare/unparse/unit.ha \
$(STDLIB)/hare/unparse/util.ha
-$(TESTCACHE)/hare/unparse/hare_unparse-any.ssa: $(testlib_hare_unparse_any_srcs) $(testlib_rt) $(testlib_fmt) $(testlib_io) $(testlib_strio) $(testlib_hare_ast)
+$(TESTCACHE)/hare/unparse/hare_unparse-any.ssa: $(testlib_hare_unparse_any_srcs) $(testlib_rt) $(testlib_fmt_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_strio_$(PLATFORM)) $(testlib_hare_ast_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/hare/unparse
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhare::unparse \
@@ -2029,7 +2623,7 @@ $(TESTCACHE)/hare/unparse/hare_unparse-any.ssa: $(testlib_hare_unparse_any_srcs)
testlib_hash_any_srcs= \
$(STDLIB)/hash/hash.ha
-$(TESTCACHE)/hash/hash-any.ssa: $(testlib_hash_any_srcs) $(testlib_rt) $(testlib_io) $(testlib_fmt)
+$(TESTCACHE)/hash/hash-any.ssa: $(testlib_hash_any_srcs) $(testlib_rt) $(testlib_io_$(PLATFORM)) $(testlib_fmt_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/hash
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhash \
@@ -2039,7 +2633,7 @@ $(TESTCACHE)/hash/hash-any.ssa: $(testlib_hash_any_srcs) $(testlib_rt) $(testlib
testlib_hash_adler32_any_srcs= \
$(STDLIB)/hash/adler32/adler32.ha
-$(TESTCACHE)/hash/adler32/hash_adler32-any.ssa: $(testlib_hash_adler32_any_srcs) $(testlib_rt) $(testlib_endian) $(testlib_hash) $(testlib_io) $(testlib_strings)
+$(TESTCACHE)/hash/adler32/hash_adler32-any.ssa: $(testlib_hash_adler32_any_srcs) $(testlib_rt) $(testlib_endian_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/hash/adler32
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhash::adler32 \
@@ -2049,7 +2643,7 @@ $(TESTCACHE)/hash/adler32/hash_adler32-any.ssa: $(testlib_hash_adler32_any_srcs)
testlib_hash_crc16_any_srcs= \
$(STDLIB)/hash/crc16/crc16.ha
-$(TESTCACHE)/hash/crc16/hash_crc16-any.ssa: $(testlib_hash_crc16_any_srcs) $(testlib_rt) $(testlib_endian) $(testlib_hash) $(testlib_io) $(testlib_strings)
+$(TESTCACHE)/hash/crc16/hash_crc16-any.ssa: $(testlib_hash_crc16_any_srcs) $(testlib_rt) $(testlib_endian_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/hash/crc16
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhash::crc16 \
@@ -2059,7 +2653,7 @@ $(TESTCACHE)/hash/crc16/hash_crc16-any.ssa: $(testlib_hash_crc16_any_srcs) $(tes
testlib_hash_crc32_any_srcs= \
$(STDLIB)/hash/crc32/crc32.ha
-$(TESTCACHE)/hash/crc32/hash_crc32-any.ssa: $(testlib_hash_crc32_any_srcs) $(testlib_rt) $(testlib_endian) $(testlib_hash) $(testlib_io) $(testlib_strings)
+$(TESTCACHE)/hash/crc32/hash_crc32-any.ssa: $(testlib_hash_crc32_any_srcs) $(testlib_rt) $(testlib_endian_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/hash/crc32
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhash::crc32 \
@@ -2069,7 +2663,7 @@ $(TESTCACHE)/hash/crc32/hash_crc32-any.ssa: $(testlib_hash_crc32_any_srcs) $(tes
testlib_hash_crc64_any_srcs= \
$(STDLIB)/hash/crc64/crc64.ha
-$(TESTCACHE)/hash/crc64/hash_crc64-any.ssa: $(testlib_hash_crc64_any_srcs) $(testlib_rt) $(testlib_endian) $(testlib_hash) $(testlib_io) $(testlib_strings)
+$(TESTCACHE)/hash/crc64/hash_crc64-any.ssa: $(testlib_hash_crc64_any_srcs) $(testlib_rt) $(testlib_endian_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/hash/crc64
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhash::crc64 \
@@ -2079,7 +2673,7 @@ $(TESTCACHE)/hash/crc64/hash_crc64-any.ssa: $(testlib_hash_crc64_any_srcs) $(tes
testlib_hash_fnv_any_srcs= \
$(STDLIB)/hash/fnv/fnv.ha
-$(TESTCACHE)/hash/fnv/hash_fnv-any.ssa: $(testlib_hash_fnv_any_srcs) $(testlib_rt) $(testlib_hash) $(testlib_io) $(testlib_strings)
+$(TESTCACHE)/hash/fnv/hash_fnv-any.ssa: $(testlib_hash_fnv_any_srcs) $(testlib_rt) $(testlib_hash_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/hash/fnv
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhash::fnv \
@@ -2103,12 +2697,36 @@ testlib_io_linux_srcs= \
$(STDLIB)/io/+test/limit.ha \
$(STDLIB)/io/+test/stream.ha
-$(TESTCACHE)/io/io-linux.ssa: $(testlib_io_linux_srcs) $(testlib_rt) $(testlib_strings) $(testlib_errors)
+# io (+freebsd)
+testlib_io_freebsd_srcs= \
+ $(STDLIB)/io/arch+$(ARCH).ha \
+ $(STDLIB)/io/println+freebsd.ha \
+ $(STDLIB)/io/+freebsd/file.ha \
+ $(STDLIB)/io/copy.ha \
+ $(STDLIB)/io/drain.ha \
+ $(STDLIB)/io/empty.ha \
+ $(STDLIB)/io/filestream.ha \
+ $(STDLIB)/io/handle.ha \
+ $(STDLIB)/io/limit.ha \
+ $(STDLIB)/io/stream.ha \
+ $(STDLIB)/io/tee.ha \
+ $(STDLIB)/io/types.ha \
+ $(STDLIB)/io/+test/copy.ha \
+ $(STDLIB)/io/+test/limit.ha \
+ $(STDLIB)/io/+test/stream.ha
+
+$(TESTCACHE)/io/io-linux.ssa: $(testlib_io_linux_srcs) $(testlib_rt) $(testlib_strings_$(PLATFORM)) $(testlib_errors_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/io
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nio \
-t$(TESTCACHE)/io/io.td $(testlib_io_linux_srcs)
+$(TESTCACHE)/io/io-freebsd.ssa: $(testlib_io_freebsd_srcs) $(testlib_rt) $(testlib_strings_$(PLATFORM)) $(testlib_errors_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/io
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nio \
+ -t$(TESTCACHE)/io/io.td $(testlib_io_freebsd_srcs)
+
# iobus::io_uring (+linux)
testlib_iobus_io_uring_linux_srcs= \
$(STDLIB)/iobus/io_uring/bus.ha \
@@ -2117,7 +2735,7 @@ testlib_iobus_io_uring_linux_srcs= \
$(STDLIB)/iobus/io_uring/pool.ha \
$(STDLIB)/iobus/io_uring/types.ha
-$(TESTCACHE)/iobus/io_uring/iobus_io_uring-linux.ssa: $(testlib_iobus_io_uring_linux_srcs) $(testlib_rt) $(testlib_errors) $(testlib_io) $(testlib_linux_io_uring) $(testlib_net_ip) $(testlib_unix_poll)
+$(TESTCACHE)/iobus/io_uring/iobus_io_uring-linux.ssa: $(testlib_iobus_io_uring_linux_srcs) $(testlib_rt) $(testlib_errors_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_linux_io_uring_$(PLATFORM)) $(testlib_net_ip_$(PLATFORM)) $(testlib_unix_poll_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/iobus/io_uring
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Niobus::io_uring \
@@ -2128,7 +2746,7 @@ testlib_linux_linux_srcs= \
$(STDLIB)/linux/start.ha \
$(STDLIB)/linux/env.ha
-$(TESTCACHE)/linux/linux-linux.ssa: $(testlib_linux_linux_srcs) $(testlib_rt) $(testlib_format_elf)
+$(TESTCACHE)/linux/linux-linux.ssa: $(testlib_linux_linux_srcs) $(testlib_rt) $(testlib_format_elf_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/linux
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nlinux \
@@ -2138,7 +2756,7 @@ $(TESTCACHE)/linux/linux-linux.ssa: $(testlib_linux_linux_srcs) $(testlib_rt) $(
testlib_linux_signalfd_linux_srcs= \
$(STDLIB)/linux/signalfd/signalfd.ha
-$(TESTCACHE)/linux/signalfd/linux_signalfd-linux.ssa: $(testlib_linux_signalfd_linux_srcs) $(testlib_rt) $(testlib_errors)
+$(TESTCACHE)/linux/signalfd/linux_signalfd-linux.ssa: $(testlib_linux_signalfd_linux_srcs) $(testlib_rt) $(testlib_errors_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/linux/signalfd
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nlinux::signalfd \
@@ -2153,7 +2771,7 @@ testlib_linux_io_uring_linux_srcs= \
$(STDLIB)/linux/io_uring/sqe.ha \
$(STDLIB)/linux/io_uring/uring.ha
-$(TESTCACHE)/linux/io_uring/linux_io_uring-linux.ssa: $(testlib_linux_io_uring_linux_srcs) $(testlib_rt) $(testlib_errors) $(testlib_types)
+$(TESTCACHE)/linux/io_uring/linux_io_uring-linux.ssa: $(testlib_linux_io_uring_linux_srcs) $(testlib_rt) $(testlib_errors_$(PLATFORM)) $(testlib_types_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/linux/io_uring
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nlinux::io_uring \
@@ -2163,7 +2781,7 @@ $(TESTCACHE)/linux/io_uring/linux_io_uring-linux.ssa: $(testlib_linux_io_uring_l
testlib_linux_vdso_linux_srcs= \
$(STDLIB)/linux/vdso/vdso.ha
-$(TESTCACHE)/linux/vdso/linux_vdso-linux.ssa: $(testlib_linux_vdso_linux_srcs) $(testlib_rt) $(testlib_linux) $(testlib_strings) $(testlib_format_elf)
+$(TESTCACHE)/linux/vdso/linux_vdso-linux.ssa: $(testlib_linux_vdso_linux_srcs) $(testlib_rt) $(testlib_linux_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_format_elf_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/linux/vdso
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nlinux::vdso \
@@ -2178,7 +2796,7 @@ testlib_math_any_srcs= \
$(STDLIB)/math/trig.ha \
$(STDLIB)/math/data+test.ha
-$(TESTCACHE)/math/math-any.ssa: $(testlib_math_any_srcs) $(testlib_rt) $(testlib_types)
+$(TESTCACHE)/math/math-any.ssa: $(testlib_math_any_srcs) $(testlib_rt) $(testlib_types_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/math
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nmath \
@@ -2190,12 +2808,24 @@ testlib_net_linux_srcs= \
$(STDLIB)/net/errors.ha \
$(STDLIB)/net/listener.ha
-$(TESTCACHE)/net/net-linux.ssa: $(testlib_net_linux_srcs) $(testlib_rt) $(testlib_io) $(testlib_os) $(testlib_strings) $(testlib_net_ip) $(testlib_errors) $(testlib_rt) $(testlib_fmt)
+$(TESTCACHE)/net/net-linux.ssa: $(testlib_net_linux_srcs) $(testlib_rt) $(testlib_io_$(PLATFORM)) $(testlib_os_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_net_ip_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_rt_$(PLATFORM)) $(testlib_fmt_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/net
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nnet \
-t$(TESTCACHE)/net/net.td $(testlib_net_linux_srcs)
+# net (+freebsd)
+testlib_net_freebsd_srcs= \
+ $(STDLIB)/net/+freebsd.ha \
+ $(STDLIB)/net/errors.ha \
+ $(STDLIB)/net/listener.ha
+
+$(TESTCACHE)/net/net-freebsd.ssa: $(testlib_net_freebsd_srcs) $(testlib_rt) $(testlib_io_$(PLATFORM)) $(testlib_os_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_net_ip_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_rt_$(PLATFORM)) $(testlib_fmt_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/net
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nnet \
+ -t$(TESTCACHE)/net/net.td $(testlib_net_freebsd_srcs)
+
# net::dial (+any)
testlib_net_dial_any_srcs= \
$(STDLIB)/net/dial/registry.ha \
@@ -2203,7 +2833,7 @@ testlib_net_dial_any_srcs= \
$(STDLIB)/net/dial/ip.ha \
$(STDLIB)/net/dial/resolve.ha
-$(TESTCACHE)/net/dial/net_dial-any.ssa: $(testlib_net_dial_any_srcs) $(testlib_rt) $(testlib_io) $(testlib_net) $(testlib_net_ip) $(testlib_net_tcp) $(testlib_net_udp) $(testlib_net_dns) $(testlib_crypto_random) $(testlib_strconv) $(testlib_strings) $(testlib_unix_hosts)
+$(TESTCACHE)/net/dial/net_dial-any.ssa: $(testlib_net_dial_any_srcs) $(testlib_rt) $(testlib_io_$(PLATFORM)) $(testlib_net_$(PLATFORM)) $(testlib_net_ip_$(PLATFORM)) $(testlib_net_tcp_$(PLATFORM)) $(testlib_net_udp_$(PLATFORM)) $(testlib_net_dns_$(PLATFORM)) $(testlib_crypto_random_$(PLATFORM)) $(testlib_strconv_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_unix_hosts_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/net/dial
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nnet::dial \
@@ -2217,7 +2847,7 @@ testlib_net_dns_any_srcs= \
$(STDLIB)/net/dns/query.ha \
$(STDLIB)/net/dns/types.ha
-$(TESTCACHE)/net/dns/net_dns-any.ssa: $(testlib_net_dns_any_srcs) $(testlib_rt) $(testlib_ascii) $(testlib_endian) $(testlib_net) $(testlib_net_udp) $(testlib_net_ip) $(testlib_fmt) $(testlib_strings) $(testlib_unix_resolvconf) $(testlib_unix_poll) $(testlib_rt) $(testlib_time) $(testlib_errors)
+$(TESTCACHE)/net/dns/net_dns-any.ssa: $(testlib_net_dns_any_srcs) $(testlib_rt) $(testlib_ascii_$(PLATFORM)) $(testlib_endian_$(PLATFORM)) $(testlib_net_$(PLATFORM)) $(testlib_net_udp_$(PLATFORM)) $(testlib_net_ip_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_unix_resolvconf_$(PLATFORM)) $(testlib_unix_poll_$(PLATFORM)) $(testlib_rt_$(PLATFORM)) $(testlib_time_$(PLATFORM)) $(testlib_errors_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/net/dns
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nnet::dns \
@@ -2225,39 +2855,74 @@ $(TESTCACHE)/net/dns/net_dns-any.ssa: $(testlib_net_dns_any_srcs) $(testlib_rt)
# net::ip (+linux)
testlib_net_ip_linux_srcs= \
- $(STDLIB)/net/ip/ip.ha \
$(STDLIB)/net/ip/+linux.ha \
+ $(STDLIB)/net/ip/ip.ha \
+ $(STDLIB)/net/ip/+test.ha
+
+# net::ip (+freebsd)
+testlib_net_ip_freebsd_srcs= \
+ $(STDLIB)/net/ip/+freebsd.ha \
+ $(STDLIB)/net/ip/ip.ha \
$(STDLIB)/net/ip/+test.ha
-$(TESTCACHE)/net/ip/net_ip-linux.ssa: $(testlib_net_ip_linux_srcs) $(testlib_rt) $(testlib_bytes) $(testlib_io) $(testlib_strconv) $(testlib_strings) $(testlib_strio) $(testlib_fmt)
+$(TESTCACHE)/net/ip/net_ip-linux.ssa: $(testlib_net_ip_linux_srcs) $(testlib_rt) $(testlib_bytes_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_strconv_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_strio_$(PLATFORM)) $(testlib_fmt_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/net/ip
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nnet::ip \
-t$(TESTCACHE)/net/ip/net_ip.td $(testlib_net_ip_linux_srcs)
+$(TESTCACHE)/net/ip/net_ip-freebsd.ssa: $(testlib_net_ip_freebsd_srcs) $(testlib_rt) $(testlib_bytes_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_strconv_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_strio_$(PLATFORM)) $(testlib_fmt_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/net/ip
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nnet::ip \
+ -t$(TESTCACHE)/net/ip/net_ip.td $(testlib_net_ip_freebsd_srcs)
+
# net::tcp (+linux)
testlib_net_tcp_linux_srcs= \
$(STDLIB)/net/tcp/+linux.ha \
$(STDLIB)/net/tcp/listener.ha \
$(STDLIB)/net/tcp/options.ha
-$(TESTCACHE)/net/tcp/net_tcp-linux.ssa: $(testlib_net_tcp_linux_srcs) $(testlib_rt) $(testlib_io) $(testlib_net) $(testlib_net_ip) $(testlib_os) $(testlib_rt)
+$(TESTCACHE)/net/tcp/net_tcp-linux.ssa: $(testlib_net_tcp_linux_srcs) $(testlib_rt) $(testlib_io_$(PLATFORM)) $(testlib_net_$(PLATFORM)) $(testlib_net_ip_$(PLATFORM)) $(testlib_os_$(PLATFORM)) $(testlib_rt_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/net/tcp
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nnet::tcp \
-t$(TESTCACHE)/net/tcp/net_tcp.td $(testlib_net_tcp_linux_srcs)
+# net::tcp (+freebsd)
+testlib_net_tcp_freebsd_srcs= \
+ $(STDLIB)/net/tcp/+freebsd.ha \
+ $(STDLIB)/net/tcp/listener.ha \
+ $(STDLIB)/net/tcp/options.ha
+
+$(TESTCACHE)/net/tcp/net_tcp-freebsd.ssa: $(testlib_net_tcp_freebsd_srcs) $(testlib_rt) $(testlib_io_$(PLATFORM)) $(testlib_net_$(PLATFORM)) $(testlib_net_ip_$(PLATFORM)) $(testlib_os_$(PLATFORM)) $(testlib_rt_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/net/tcp
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nnet::tcp \
+ -t$(TESTCACHE)/net/tcp/net_tcp.td $(testlib_net_tcp_freebsd_srcs)
+
# net::udp (+linux)
testlib_net_udp_linux_srcs= \
$(STDLIB)/net/udp/+linux.ha \
$(STDLIB)/net/udp/options.ha
-$(TESTCACHE)/net/udp/net_udp-linux.ssa: $(testlib_net_udp_linux_srcs) $(testlib_rt) $(testlib_net) $(testlib_net_ip) $(testlib_errors) $(testlib_rt) $(testlib_os) $(testlib_io)
+$(TESTCACHE)/net/udp/net_udp-linux.ssa: $(testlib_net_udp_linux_srcs) $(testlib_rt) $(testlib_net_$(PLATFORM)) $(testlib_net_ip_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_rt_$(PLATFORM)) $(testlib_os_$(PLATFORM)) $(testlib_io_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/net/udp
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nnet::udp \
-t$(TESTCACHE)/net/udp/net_udp.td $(testlib_net_udp_linux_srcs)
+# net::udp (+freebsd)
+testlib_net_udp_freebsd_srcs= \
+ $(STDLIB)/net/udp/+freebsd.ha \
+ $(STDLIB)/net/udp/options.ha
+
+$(TESTCACHE)/net/udp/net_udp-freebsd.ssa: $(testlib_net_udp_freebsd_srcs) $(testlib_rt) $(testlib_net_$(PLATFORM)) $(testlib_net_ip_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_rt_$(PLATFORM)) $(testlib_os_$(PLATFORM)) $(testlib_io_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/net/udp
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nnet::udp \
+ -t$(TESTCACHE)/net/udp/net_udp.td $(testlib_net_udp_freebsd_srcs)
+
# net::unix (+linux)
testlib_net_unix_linux_srcs= \
$(STDLIB)/net/unix/+linux.ha \
@@ -2266,12 +2931,26 @@ testlib_net_unix_linux_srcs= \
$(STDLIB)/net/unix/listener.ha \
$(STDLIB)/net/unix/options.ha
-$(TESTCACHE)/net/unix/net_unix-linux.ssa: $(testlib_net_unix_linux_srcs) $(testlib_rt) $(testlib_net) $(testlib_errors) $(testlib_os) $(testlib_io) $(testlib_strings) $(testlib_types) $(testlib_fmt) $(testlib_net_dial)
+$(TESTCACHE)/net/unix/net_unix-linux.ssa: $(testlib_net_unix_linux_srcs) $(testlib_rt) $(testlib_net_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_os_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_types_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_net_dial_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/net/unix
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nnet::unix \
-t$(TESTCACHE)/net/unix/net_unix.td $(testlib_net_unix_linux_srcs)
+# net::unix (+freebsd)
+testlib_net_unix_freebsd_srcs= \
+ $(STDLIB)/net/unix/+freebsd.ha \
+ $(STDLIB)/net/unix/addr.ha \
+ $(STDLIB)/net/unix/dial.ha \
+ $(STDLIB)/net/unix/listener.ha \
+ $(STDLIB)/net/unix/options.ha
+
+$(TESTCACHE)/net/unix/net_unix-freebsd.ssa: $(testlib_net_unix_freebsd_srcs) $(testlib_rt) $(testlib_net_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_os_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_types_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_net_dial_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/net/unix
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nnet::unix \
+ -t$(TESTCACHE)/net/unix/net_unix.td $(testlib_net_unix_freebsd_srcs)
+
# math::random (+any)
testlib_math_random_any_srcs= \
$(STDLIB)/math/random/random.ha
@@ -2291,12 +2970,27 @@ testlib_os_linux_srcs= \
$(STDLIB)/os/+linux/fs.ha \
$(STDLIB)/os/fs.ha
-$(TESTCACHE)/os/os-linux.ssa: $(testlib_os_linux_srcs) $(testlib_rt) $(testlib_io) $(testlib_strings) $(testlib_types) $(testlib_fs) $(testlib_encoding_utf8) $(testlib_bytes) $(testlib_bufio) $(testlib_errors)
+$(TESTCACHE)/os/os-linux.ssa: $(testlib_os_linux_srcs) $(testlib_rt) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_types_$(PLATFORM)) $(testlib_fs_$(PLATFORM)) $(testlib_encoding_utf8_$(PLATFORM)) $(testlib_bytes_$(PLATFORM)) $(testlib_bufio_$(PLATFORM)) $(testlib_errors_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/os
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nos \
-t$(TESTCACHE)/os/os.td $(testlib_os_linux_srcs)
+# os (+freebsd)
+testlib_os_freebsd_srcs= \
+ $(STDLIB)/os/+freebsd/environ.ha \
+ $(STDLIB)/os/+freebsd/exit.ha \
+ $(STDLIB)/os/+freebsd/dirfdfs.ha \
+ $(STDLIB)/os/+freebsd/stdfd.ha \
+ $(STDLIB)/os/+freebsd/fs.ha \
+ $(STDLIB)/os/fs.ha
+
+$(TESTCACHE)/os/os-freebsd.ssa: $(testlib_os_freebsd_srcs) $(testlib_rt) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_types_$(PLATFORM)) $(testlib_fs_$(PLATFORM)) $(testlib_encoding_utf8_$(PLATFORM)) $(testlib_bytes_$(PLATFORM)) $(testlib_bufio_$(PLATFORM)) $(testlib_errors_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/os
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nos \
+ -t$(TESTCACHE)/os/os.td $(testlib_os_freebsd_srcs)
+
# os::exec (+linux)
testlib_os_exec_linux_srcs= \
$(STDLIB)/os/exec/exec+linux.ha \
@@ -2304,12 +2998,25 @@ testlib_os_exec_linux_srcs= \
$(STDLIB)/os/exec/types.ha \
$(STDLIB)/os/exec/cmd.ha
-$(TESTCACHE)/os/exec/os_exec-linux.ssa: $(testlib_os_exec_linux_srcs) $(testlib_rt) $(testlib_os) $(testlib_strings) $(testlib_fmt) $(testlib_bytes) $(testlib_path) $(testlib_errors)
+$(TESTCACHE)/os/exec/os_exec-linux.ssa: $(testlib_os_exec_linux_srcs) $(testlib_rt) $(testlib_os_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_bytes_$(PLATFORM)) $(testlib_path_$(PLATFORM)) $(testlib_errors_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/os/exec
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nos::exec \
-t$(TESTCACHE)/os/exec/os_exec.td $(testlib_os_exec_linux_srcs)
+# os::exec (+freebsd)
+testlib_os_exec_freebsd_srcs= \
+ $(STDLIB)/os/exec/exec+freebsd.ha \
+ $(STDLIB)/os/exec/process+freebsd.ha \
+ $(STDLIB)/os/exec/types.ha \
+ $(STDLIB)/os/exec/cmd.ha
+
+$(TESTCACHE)/os/exec/os_exec-freebsd.ssa: $(testlib_os_exec_freebsd_srcs) $(testlib_rt) $(testlib_os_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_bytes_$(PLATFORM)) $(testlib_path_$(PLATFORM)) $(testlib_errors_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/os/exec
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nos::exec \
+ -t$(TESTCACHE)/os/exec/os_exec.td $(testlib_os_exec_freebsd_srcs)
+
# path (+any)
testlib_path_any_srcs= \
$(STDLIB)/path/+$(PLATFORM).ha \
@@ -2318,7 +3025,7 @@ testlib_path_any_srcs= \
$(STDLIB)/path/names.ha \
$(STDLIB)/path/iter.ha
-$(TESTCACHE)/path/path-any.ssa: $(testlib_path_any_srcs) $(testlib_rt) $(testlib_strings) $(testlib_bufio) $(testlib_bytes)
+$(TESTCACHE)/path/path-any.ssa: $(testlib_path_any_srcs) $(testlib_rt) $(testlib_strings_$(PLATFORM)) $(testlib_bufio_$(PLATFORM)) $(testlib_bytes_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/path
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Npath \
@@ -2329,7 +3036,7 @@ testlib_slice_any_srcs= \
$(STDLIB)/slice/reverse.ha \
$(STDLIB)/slice/void.ha
-$(TESTCACHE)/slice/slice-any.ssa: $(testlib_slice_any_srcs) $(testlib_rt) $(testlib_types)
+$(TESTCACHE)/slice/slice-any.ssa: $(testlib_slice_any_srcs) $(testlib_rt) $(testlib_types_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/slice
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nslice \
@@ -2361,7 +3068,7 @@ testlib_strconv_any_srcs= \
$(STDLIB)/strconv/+test/stou.ha \
$(STDLIB)/strconv/+test/stoi.ha
-$(TESTCACHE)/strconv/strconv-any.ssa: $(testlib_strconv_any_srcs) $(testlib_rt) $(testlib_types) $(testlib_strings) $(testlib_ascii) $(testlib_math)
+$(TESTCACHE)/strconv/strconv-any.ssa: $(testlib_strconv_any_srcs) $(testlib_rt) $(testlib_types_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_ascii_$(PLATFORM)) $(testlib_math_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/strconv
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nstrconv \
@@ -2381,7 +3088,7 @@ testlib_strings_any_srcs= \
$(STDLIB)/strings/index.ha \
$(STDLIB)/strings/trim.ha
-$(TESTCACHE)/strings/strings-any.ssa: $(testlib_strings_any_srcs) $(testlib_rt) $(testlib_bytes) $(testlib_encoding_utf8) $(testlib_types)
+$(TESTCACHE)/strings/strings-any.ssa: $(testlib_strings_any_srcs) $(testlib_rt) $(testlib_bytes_$(PLATFORM)) $(testlib_encoding_utf8_$(PLATFORM)) $(testlib_types_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/strings
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nstrings \
@@ -2393,7 +3100,7 @@ testlib_strio_any_srcs= \
$(STDLIB)/strio/fixed.ha \
$(STDLIB)/strio/ops.ha
-$(TESTCACHE)/strio/strio-any.ssa: $(testlib_strio_any_srcs) $(testlib_rt) $(testlib_io) $(testlib_strings) $(testlib_encoding_utf8) $(testlib_errors)
+$(TESTCACHE)/strio/strio-any.ssa: $(testlib_strio_any_srcs) $(testlib_rt) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_encoding_utf8_$(PLATFORM)) $(testlib_errors_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/strio
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nstrio \
@@ -2403,12 +3110,22 @@ $(TESTCACHE)/strio/strio-any.ssa: $(testlib_strio_any_srcs) $(testlib_rt) $(test
testlib_temp_linux_srcs= \
$(STDLIB)/temp/+linux.ha
-$(TESTCACHE)/temp/temp-linux.ssa: $(testlib_temp_linux_srcs) $(testlib_rt) $(testlib_crypto_random) $(testlib_encoding_hex) $(testlib_fs) $(testlib_io) $(testlib_os) $(testlib_path) $(testlib_strio) $(testlib_fmt) $(testlib_strings)
+$(TESTCACHE)/temp/temp-linux.ssa: $(testlib_temp_linux_srcs) $(testlib_rt) $(testlib_crypto_random_$(PLATFORM)) $(testlib_encoding_hex_$(PLATFORM)) $(testlib_fs_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_os_$(PLATFORM)) $(testlib_path_$(PLATFORM)) $(testlib_strio_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/temp
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ntemp \
-t$(TESTCACHE)/temp/temp.td $(testlib_temp_linux_srcs)
+# temp (+freebsd)
+testlib_temp_freebsd_srcs= \
+ $(STDLIB)/temp/+freebsd.ha
+
+$(TESTCACHE)/temp/temp-freebsd.ssa: $(testlib_temp_freebsd_srcs) $(testlib_rt) $(testlib_crypto_random_$(PLATFORM)) $(testlib_encoding_hex_$(PLATFORM)) $(testlib_fs_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_os_$(PLATFORM)) $(testlib_path_$(PLATFORM)) $(testlib_strio_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_strings_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/temp
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ntemp \
+ -t$(TESTCACHE)/temp/temp.td $(testlib_temp_freebsd_srcs)
+
# time (+linux)
testlib_time_linux_srcs= \
$(STDLIB)/time/+linux/functions.ha \
@@ -2416,12 +3133,24 @@ testlib_time_linux_srcs= \
$(STDLIB)/time/arithm.ha \
$(STDLIB)/time/types.ha
-$(TESTCACHE)/time/time-linux.ssa: $(testlib_time_linux_srcs) $(testlib_rt) $(testlib_linux_vdso)
+$(TESTCACHE)/time/time-linux.ssa: $(testlib_time_linux_srcs) $(testlib_rt) $(testlib_linux_vdso_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/time
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ntime \
-t$(TESTCACHE)/time/time.td $(testlib_time_linux_srcs)
+# time (+freebsd)
+testlib_time_freebsd_srcs= \
+ $(STDLIB)/time/+freebsd/functions.ha \
+ $(STDLIB)/time/arithm.ha \
+ $(STDLIB)/time/types.ha
+
+$(TESTCACHE)/time/time-freebsd.ssa: $(testlib_time_freebsd_srcs) $(testlib_rt)
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/time
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ntime \
+ -t$(TESTCACHE)/time/time.td $(testlib_time_freebsd_srcs)
+
# types (+any)
testlib_types_any_srcs= \
$(STDLIB)/types/limits.ha \
@@ -2445,17 +3174,31 @@ testlib_unix_linux_srcs= \
$(STDLIB)/unix/getuid.ha \
$(STDLIB)/unix/setuid.ha
-$(TESTCACHE)/unix/unix-linux.ssa: $(testlib_unix_linux_srcs) $(testlib_rt) $(testlib_errors) $(testlib_fs)
+$(TESTCACHE)/unix/unix-linux.ssa: $(testlib_unix_linux_srcs) $(testlib_rt) $(testlib_errors_$(PLATFORM)) $(testlib_fs_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/unix
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nunix \
-t$(TESTCACHE)/unix/unix.td $(testlib_unix_linux_srcs)
+# unix (+freebsd)
+testlib_unix_freebsd_srcs= \
+ $(STDLIB)/unix/+freebsd/nice.ha \
+ $(STDLIB)/unix/+freebsd/pipe.ha \
+ $(STDLIB)/unix/+freebsd/umask.ha \
+ $(STDLIB)/unix/getuid.ha \
+ $(STDLIB)/unix/setuid.ha
+
+$(TESTCACHE)/unix/unix-freebsd.ssa: $(testlib_unix_freebsd_srcs) $(testlib_rt) $(testlib_errors_$(PLATFORM)) $(testlib_fs_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/unix
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nunix \
+ -t$(TESTCACHE)/unix/unix.td $(testlib_unix_freebsd_srcs)
+
# unix::hosts (+any)
testlib_unix_hosts_any_srcs= \
$(STDLIB)/unix/hosts/lookup.ha
-$(TESTCACHE)/unix/hosts/unix_hosts-any.ssa: $(testlib_unix_hosts_any_srcs) $(testlib_rt) $(testlib_os) $(testlib_io) $(testlib_bufio) $(testlib_net_ip) $(testlib_strings)
+$(TESTCACHE)/unix/hosts/unix_hosts-any.ssa: $(testlib_unix_hosts_any_srcs) $(testlib_rt) $(testlib_os_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_bufio_$(PLATFORM)) $(testlib_net_ip_$(PLATFORM)) $(testlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/unix/hosts
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nunix::hosts \
@@ -2467,7 +3210,7 @@ testlib_unix_passwd_any_srcs= \
$(STDLIB)/unix/passwd/passwd.ha \
$(STDLIB)/unix/passwd/types.ha
-$(TESTCACHE)/unix/passwd/unix_passwd-any.ssa: $(testlib_unix_passwd_any_srcs) $(testlib_rt) $(testlib_bufio) $(testlib_io) $(testlib_os) $(testlib_strconv) $(testlib_strings)
+$(TESTCACHE)/unix/passwd/unix_passwd-any.ssa: $(testlib_unix_passwd_any_srcs) $(testlib_rt) $(testlib_bufio_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_os_$(PLATFORM)) $(testlib_strconv_$(PLATFORM)) $(testlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/unix/passwd
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nunix::passwd \
@@ -2477,17 +3220,27 @@ $(TESTCACHE)/unix/passwd/unix_passwd-any.ssa: $(testlib_unix_passwd_any_srcs) $(
testlib_unix_poll_linux_srcs= \
$(STDLIB)/unix/poll/+linux.ha
-$(TESTCACHE)/unix/poll/unix_poll-linux.ssa: $(testlib_unix_poll_linux_srcs) $(testlib_rt) $(testlib_rt) $(testlib_errors) $(testlib_time)
+$(TESTCACHE)/unix/poll/unix_poll-linux.ssa: $(testlib_unix_poll_linux_srcs) $(testlib_rt) $(testlib_rt_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_time_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/unix/poll
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nunix::poll \
-t$(TESTCACHE)/unix/poll/unix_poll.td $(testlib_unix_poll_linux_srcs)
+# unix::poll (+freebsd)
+testlib_unix_poll_freebsd_srcs= \
+ $(STDLIB)/unix/poll/+freebsd.ha
+
+$(TESTCACHE)/unix/poll/unix_poll-freebsd.ssa: $(testlib_unix_poll_freebsd_srcs) $(testlib_rt) $(testlib_rt_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_time_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/unix/poll
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nunix::poll \
+ -t$(TESTCACHE)/unix/poll/unix_poll.td $(testlib_unix_poll_freebsd_srcs)
+
# unix::resolvconf (+any)
testlib_unix_resolvconf_any_srcs= \
$(STDLIB)/unix/resolvconf/load.ha
-$(TESTCACHE)/unix/resolvconf/unix_resolvconf-any.ssa: $(testlib_unix_resolvconf_any_srcs) $(testlib_rt) $(testlib_os) $(testlib_io) $(testlib_bufio) $(testlib_net_ip) $(testlib_strings)
+$(TESTCACHE)/unix/resolvconf/unix_resolvconf-any.ssa: $(testlib_unix_resolvconf_any_srcs) $(testlib_rt) $(testlib_os_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_bufio_$(PLATFORM)) $(testlib_net_ip_$(PLATFORM)) $(testlib_strings_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/unix/resolvconf
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nunix::resolvconf \
@@ -2500,17 +3253,30 @@ testlib_unix_tty_linux_srcs= \
$(STDLIB)/unix/tty/+linux/open.ha \
$(STDLIB)/unix/tty/+linux/winsize.ha
-$(TESTCACHE)/unix/tty/unix_tty-linux.ssa: $(testlib_unix_tty_linux_srcs) $(testlib_rt) $(testlib_rt) $(testlib_fs) $(testlib_io) $(testlib_os)
+$(TESTCACHE)/unix/tty/unix_tty-linux.ssa: $(testlib_unix_tty_linux_srcs) $(testlib_rt) $(testlib_rt_$(PLATFORM)) $(testlib_fs_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_os_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/unix/tty
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nunix::tty \
-t$(TESTCACHE)/unix/tty/unix_tty.td $(testlib_unix_tty_linux_srcs)
+# unix::tty (+freebsd)
+testlib_unix_tty_freebsd_srcs= \
+ $(STDLIB)/unix/tty/types.ha \
+ $(STDLIB)/unix/tty/+freebsd/isatty.ha \
+ $(STDLIB)/unix/tty/+freebsd/open.ha \
+ $(STDLIB)/unix/tty/+freebsd/winsize.ha
+
+$(TESTCACHE)/unix/tty/unix_tty-freebsd.ssa: $(testlib_unix_tty_freebsd_srcs) $(testlib_rt) $(testlib_rt_$(PLATFORM)) $(testlib_fs_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_os_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/unix/tty
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nunix::tty \
+ -t$(TESTCACHE)/unix/tty/unix_tty.td $(testlib_unix_tty_freebsd_srcs)
+
# uuid (+any)
testlib_uuid_any_srcs= \
$(STDLIB)/uuid/uuid.ha
-$(TESTCACHE)/uuid/uuid-any.ssa: $(testlib_uuid_any_srcs) $(testlib_rt) $(testlib_crypto_random) $(testlib_strio) $(testlib_fmt) $(testlib_endian) $(testlib_io) $(testlib_bytes) $(testlib_bufio) $(testlib_strings) $(testlib_strconv)
+$(TESTCACHE)/uuid/uuid-any.ssa: $(testlib_uuid_any_srcs) $(testlib_rt) $(testlib_crypto_random_$(PLATFORM)) $(testlib_strio_$(PLATFORM)) $(testlib_fmt_$(PLATFORM)) $(testlib_endian_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_bytes_$(PLATFORM)) $(testlib_bufio_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_strconv_$(PLATFORM))
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/uuid
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nuuid \
diff --git a/temp/+freebsd.ha b/temp/+freebsd.ha
@@ -0,0 +1,98 @@
+use crypto::random;
+use encoding::hex;
+use errors;
+use fmt;
+use fs;
+use io;
+use os;
+use path;
+use strio;
+use strings;
+
+fn get_tmpdir() str = os::tryenv("TMPDIR", "/tmp");
+
+// Creates an unnamed temporary file. The file may or may not have a name; not
+// all systems support the creation of temporary inodes which are not linked to
+// any directory. If it is necessary to create a real file, it will be removed
+// when the stream is closed.
+//
+// The I/O mode must be either [[io::mode::WRITE]] or [[io::mode::RDWR]].
+//
+// Only one variadic argument may be provided, if at all, to specify the mode of
+// the new file. The default is 0o644.
+export fn file(
+ iomode: io::mode,
+ mode: fs::mode...
+) (io::file | fs::error) = {
+ // TODO: Add a custom "close" function which removes the named file
+ let file = named(os::cwd, get_tmpdir(), iomode, mode...)?;
+ free(file.1);
+ return file.0;
+};
+
+// Creates a named temporary file in the given directory of the given
+// filesystem. The caller is responsible for removing the file and freeing the
+// name when they're done with it.
+//
+// The I/O mode must be either [[io::mode::WRITE]] or [[io::mode::RDWR]].
+//
+// Only one variadic argument may be provided, if at all, to specify the mode of
+// the new file. The default is 0o644.
+export fn named(
+ fs: *fs::fs,
+ path: str,
+ iomode: io::mode,
+ mode: fs::mode...
+) ((io::file, str) | fs::error) = {
+ assert(iomode == io::mode::WRITE || iomode == io::mode::RDWR);
+ assert(len(mode) == 0 || len(mode) == 1);
+
+ let fmode = if (len(mode) != 0) mode[0] else 0o644: fs::mode;
+ let oflags = fs::flags::EXCL | fs::flags::CLOEXEC;
+ if (iomode == io::mode::RDWR) {
+ oflags |= fs::flags::RDWR;
+ } else {
+ oflags |= fs::flags::WRONLY;
+ };
+
+ // TODO: Use path::pathbuf
+ static let pathbuf: [4096]u8 = [0...];
+ for (true) {
+ let rand: [size(u64)]u8 = [0...];
+ random::buffer(rand);
+ const id = *(&rand[0]: *u64);
+ const fpath = fmt::bsprintf(pathbuf, "{}/temp.{}", path, id);
+ match (fs::create_file(fs, fpath, fmode, oflags)) {
+ case errors::exists =>
+ continue;
+ case err: fs::error =>
+ return err;
+ case f: io::file =>
+ return (f, strings::dup(fpath));
+ };
+ };
+ abort(); // Unreachable
+};
+
+// Creates a temporary directory. This function only guarantees that the
+// directory will have a unique name and be placed in the system temp directory,
+// but not that it will be removed automatically; the caller must remove it when
+// they're done using it via [[os::rmdir]] or [[os::rmdirall]].
+//
+// The caller must free the return value.
+export fn dir() str = {
+ let buf: [8]u8 = [0...], name: [16]u8 = [0...];
+ random::buffer(buf[..]);
+
+ let sink = strio::fixed(name);
+ defer io::close(sink);
+ hex::encode(sink, buf) as size;
+ let name = strio::string(sink);
+
+ let path = path::join(get_tmpdir(), name);
+ match (os::mkdir(path)) {
+ case err: fs::error => abort("Could not create temp directory");
+ case void => void;
+ };
+ return path;
+};
diff --git a/time/+freebsd/functions.ha b/time/+freebsd/functions.ha
@@ -0,0 +1,86 @@
+use rt;
+
+// Converts a [[duration]] to an [[rt::timespec]]. This function is
+// non-portable.
+export fn duration_to_timespec(n: duration, ts: *rt::timespec) void = {
+ ts.tv_sec = n / SECOND;
+ ts.tv_nsec = n % SECOND;
+};
+
+// Converts an [[instant]] to an [[rt::timespec]]. This function is
+// non-portable.
+export fn instant_to_timespec(t: instant, ts: *rt::timespec) void = {
+ ts.tv_sec = t.sec;
+ ts.tv_nsec = t.nsec;
+};
+
+// Converts a [[rt::timespec]] to an [[rt::instant]]. This function is
+// non-portable.
+export fn timespec_to_instant(ts: rt::timespec) instant = instant {
+ sec = ts.tv_sec,
+ nsec = ts.tv_nsec,
+};
+
+// Yields the process to the kernel and returns after the requested duration.
+export fn sleep(n: duration) void = {
+ let in = rt::timespec { ... };
+ duration_to_timespec(n, &in);
+ let req = ∈
+
+ for (true) {
+ let res = rt::timespec { ... };
+ match (rt::nanosleep(req, &res)) {
+ case void =>
+ return;
+ case err: rt::errno =>
+ switch (err) {
+ case rt::EINTR =>
+ req = &res;
+ case =>
+ abort("Unexpected error from nanosleep");
+ };
+ };
+ };
+};
+
+// An enumeration of clocks available on this system. Different clocks represent
+// times from different epochs, and have different characteristics with regards
+// to leap seconds, NTP adjustments, and so on. All systems provide the REALTIME
+// and MONOTONIC clocks at least; use of other clocks is not guaranteed to be
+// portable.
+export type clock = enum {
+ // The current wall-clock time. This may jump forwards or backwards in
+ // time to account for leap seconds, NTP adjustments, etc.
+ REALTIME = 0,
+
+ // The current monotonic time. This clock measures from some undefined
+ // epoch and is not affected by leap seconds, NTP adjustments, and
+ // changes to the system time: it always increases by one second per
+ // second.
+ MONOTONIC = 4,
+
+ // TODO: Document these
+ VIRTUAL = 1,
+ PROF = 2,
+ UPTIME = 5,
+ UPTIME_PRECISE = 7,
+ UPTIME_FAST = 8,
+ REALTIME_PRECISE = 9,
+ REALTIME_FAST = 10,
+ MONOTONIC_PRECISE = 11,
+ MONOTONIC_FAST = 12,
+ SECOND = 13,
+ THREAD_CPUTIME_ID = 14,
+ PROCESS_CPUTIME_ID = 15,
+};
+
+// Returns the current time for a given clock.
+export fn now(clock: clock) instant = {
+ let tp = rt::timespec { ... };
+ match (rt::clock_gettime(clock, &tp)) {
+ case void =>
+ return timespec_to_instant(tp);
+ case err: rt::errno =>
+ abort("Unexpected error from clock_gettime");
+ };
+};
diff --git a/time/+linux/functions.ha b/time/+linux/functions.ha
@@ -107,9 +107,9 @@ export fn now(clock: clock) instant = {
abort("Unexpected error from clock_gettime");
};
match (rt::clock_gettime(clock, &tp)) {
- case void =>
- return timespec_to_instant(tp);
- case err: rt::errno =>
- abort("Unexpected error from clock_gettime");
+ case void =>
+ return timespec_to_instant(tp);
+ case err: rt::errno =>
+ abort("Unexpected error from clock_gettime");
};
};
diff --git a/unix/+freebsd/nice.ha b/unix/+freebsd/nice.ha
@@ -0,0 +1,24 @@
+use errors;
+use rt;
+
+// Adds the argument to the niceness of the current process. The input should be
+// between -20 and 19 (inclusive); lower numbers represent a higher priority.
+// Generally, you must have elevated permissions to reduce your niceness, but
+// not to increase it.
+export fn nice(inc: int) (void | errors::error) = {
+ let prio = inc;
+ if (inc > -40 && inc <= 40) {
+ prio += rt::getpriority(rt::PRIO_PROCESS, 0) as int;
+ };
+ if (prio > 19) {
+ prio = 19;
+ };
+ if (prio < -20) {
+ prio = -20;
+ };
+ match (rt::setpriority(rt::PRIO_PROCESS, 0, prio)) {
+ case void => void;
+ case err: rt::errno =>
+ return errors::errno(err);
+ };
+};
diff --git a/unix/+freebsd/pipe.ha b/unix/+freebsd/pipe.ha
@@ -0,0 +1,29 @@
+use errors;
+use io;
+use rt;
+
+// Flags to use for the [[io::file]]s returned by [[pipe]]
+// Only CLOEXEC and NONBLOCK are guaranteed to be available.
+export type pipe_flag = enum {
+ CLOEXEC = rt::O_CLOEXEC,
+ DIRECT = rt::O_DIRECT,
+ NONBLOCK = rt::O_NONBLOCK,
+};
+
+// Create a pair of two linked [[io::file]]s, such that any data written to the
+// second [[io::file]] may be read from the first. If no [[pipe_flag]]s are
+// provided, [[pipe_flag::CLOEXEC]] is used. If you pass your own flags, it is
+// recommended that you add it unless you know that you don't want it.
+export fn pipe(flags: pipe_flag...) ((io::file, io::file) | errors::error) = {
+ let fds: [2]int = [0...];
+ let flag: pipe_flag = if (len(flags) == 0) pipe_flag::CLOEXEC else 0;
+ for (let i = 0z; i < len(flags); i += 1) {
+ flag |= flags[i];
+ };
+ match (rt::pipe2(&fds, flag)) {
+ case void => void;
+ case e: rt::errno =>
+ return errors::errno(e);
+ };
+ return (fds[0], fds[1]);
+};
diff --git a/unix/+freebsd/umask.ha b/unix/+freebsd/umask.ha
@@ -0,0 +1,7 @@
+use errors;
+use fs;
+use rt;
+
+// Sets the file mode creation mask for the current process and return the
+// previous value of the mask.
+export fn umask(mode: fs::mode) fs::mode = rt::umask(mode: rt::mode_t)!: fs::mode;
diff --git a/unix/poll/+freebsd.ha b/unix/poll/+freebsd.ha
@@ -0,0 +1,48 @@
+use errors;
+use io;
+use rt;
+use time;
+
+// Events bitfield for the events and revents field of [[pollfd]].
+export type event = enum i16 {
+ POLLIN = 1,
+ POLLPRI = 2,
+ POLLOUT = 4,
+ POLLERR = 8,
+ POLLHUP = 16,
+};
+
+// A single file descriptor to be polled.
+export type pollfd = struct {
+ fd: io::file,
+ events: event,
+ revents: event,
+};
+
+// Pass this [[time::duration]] to [[poll]] to cause it wait indefinitely for
+// the next event.
+export def INDEF: time::duration = -1;
+
+// Pass this [[time::duration]] to [[poll]] to cause it to return immediately if
+// no events are available.
+export def NONBLOCK: time::duration = 0;
+
+// Polls for the desired events on a slice of [[pollfd]]s, blocking until an
+// event is available, or the timeout expires. Set the timeout to [[INDEF]] to
+// block forever, or [[NONBLOCK]] to return immediately if no events are
+// available. Returns the number of [[pollfd]] items which have events, i.e.
+// those which have revents set to a nonzero value.
+export fn poll(
+ fds: []pollfd,
+ timeout: time::duration,
+) (uint | errors::error) = {
+ let ts = rt::timespec { ... };
+ time::duration_to_timespec(timeout, &ts);
+ let ts = if (timeout == INDEF) null else &ts;
+ match (rt::ppoll(fds: *[*]pollfd, len(fds): rt::nfds_t, ts, null)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case n: int =>
+ return n: uint;
+ };
+};
diff --git a/unix/tty/+freebsd/isatty.ha b/unix/tty/+freebsd/isatty.ha
@@ -0,0 +1,14 @@
+use rt;
+use io;
+use os;
+
+// Returns whether the given stream is connected to a terminal.
+export fn isatty(fd: io::file) bool = {
+ let wsz = rt::winsize { ... };
+ match (rt::ioctl(fd, rt::TIOCGWINSZ, &wsz: *void)) {
+ case e: rt::errno =>
+ return false;
+ case r: int =>
+ return r == 0;
+ };
+};
diff --git a/unix/tty/+freebsd/open.ha b/unix/tty/+freebsd/open.ha
@@ -0,0 +1,15 @@
+use errors;
+use fs;
+use io;
+use os;
+
+// Returns a stream connected to the TTY of the current process. The caller must
+// close it using [[io::close]].
+export fn open() (io::file | error) = {
+ match (os::open("/dev/tty", fs::flags::RDWR, fs::flags::CLOEXEC)) {
+ case f: io::file =>
+ return f;
+ case fs::error =>
+ return errors::noentry;
+ };
+};
diff --git a/unix/tty/+freebsd/winsize.ha b/unix/tty/+freebsd/winsize.ha
@@ -0,0 +1,25 @@
+use errors;
+use io;
+use os;
+use rt;
+
+// Returns the dimensions of underlying terminal for an [[io::file]].
+export fn winsize(fd: io::file) (ttysize | error) = {
+ let wsz = rt::winsize { ... };
+ match (rt::ioctl(fd, rt::TIOCGWINSZ, &wsz: *void)) {
+ case e: rt::errno =>
+ switch (e: int) {
+ case rt::EBADF =>
+ return errors::invalid;
+ case rt::ENOTTY =>
+ return errors::unsupported;
+ case =>
+ abort("Unexpected error from ioctl");
+ };
+ case int =>
+ return ttysize {
+ rows = wsz.ws_row,
+ columns = wsz.ws_col,
+ };
+ };
+};