Add NetBSD Support (#2661)

* Add NetBSD Support

Includes:
- Hints to find non-compatibility libc functions
- Struct and constant definitions for sockets, polling, etc.
- Changes to the linker code to work around some quirks in the NetBSD dynamic linker
- A target triple for netbsd aarch64 so llvm builds/links the compiler properly on this platform

* Updated releasenotes and some compacting

---------

Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
This commit is contained in:
limit-ordinal
2025-12-19 13:23:06 -05:00
committed by GitHub
parent bf26898645
commit 85166bc706
21 changed files with 398 additions and 38 deletions

View File

@@ -1059,6 +1059,117 @@ jobs:
name: c3-openbsd-${{matrix.build_type}}
path: c3-openbsd-${{matrix.build_type}}.tar.gz
build-netbsd:
runs-on: ubuntu-latest
strategy:
# Don't abort runners if a single one fails
fail-fast: false
matrix:
build_type: [Release, Debug]
steps:
- uses: actions/checkout@v4
- name: NetBSD VM
uses: vmactions/netbsd-vm@v1
with:
prepare: |
/usr/sbin/pkg_add cmake llvm-19.1.7 lld-19.1.7nb1 ninja
run: |
echo "CMake"
cmake -B build -S .
cmake --build build
echo "Compile and run some examples"
cd resources
../build/c3c compile examples/base64.c3
../build/c3c compile examples/binarydigits.c3
../build/c3c compile examples/brainfk.c3
../build/c3c compile examples/factorial_macro.c3
../build/c3c compile examples/fasta.c3
../build/c3c compile examples/gameoflife.c3
../build/c3c compile examples/hash.c3
../build/c3c compile-only examples/levenshtein.c3
../build/c3c compile examples/load_world.c3
../build/c3c compile-only examples/map.c3
../build/c3c compile examples/mandelbrot.c3
../build/c3c compile examples/plus_minus.c3
../build/c3c compile examples/nbodies.c3
../build/c3c compile examples/spectralnorm.c3
../build/c3c compile examples/swap.c3
../build/c3c compile examples/contextfree/boolerr.c3
../build/c3c compile examples/contextfree/dynscope.c3
../build/c3c compile examples/contextfree/guess_number.c3
../build/c3c compile examples/contextfree/multi.c3
../build/c3c compile examples/contextfree/cleanup.c3
../build/c3c compile-run examples/hello_world_many.c3
../build/c3c compile-run examples/time.c3
../build/c3c compile-run examples/fannkuch-redux.c3
../build/c3c compile-run examples/contextfree/boolerr.c3
../build/c3c compile-run examples/load_world.c3
../build/c3c compile-run examples/process.c3
../build/c3c compile-run examples/ls.c3
../build/c3c compile-run examples/args.c3 -- foo -bar "baz baz"
cd ..
echo "Compile and run dynlib-test"
cd resources/examples/dynlib-test
../../../build/c3c -vv dynamic-lib add.c3
mv add.so libadd.so
cc test.c -L. -ladd -Wl,-rpath=.
./a.out
../../../build/c3c compile-run test.c3 -L . -l add -z -Wl,-rpath=.
cd ../../../
echo "Compile and run staticlib-test"
cd resources/examples/staticlib-test
../../../build/c3c -vv static-lib add.c3
mv add.a libadd.a
ranlib libadd.a
cc test.c -L. -ladd
./a.out
../../../build/c3c compile-run test.c3 -L . -l add
cd ../../../
echo "Compile run unit tests"
cd test
../build/c3c compile-test unit -D SLOW_TESTS
cd ..
echo "Build testproject"
cd resources/testproject
../../build/c3c run -vvv --trust=full
cd ../../
echo "Test WASM"
cd resources/testfragments
../../build/c3c compile --target wasm32 -g0 --no-entry -Os wasm4.c3
cd ../../
echo "Build testproject direct linker"
cd resources/testproject
../../build/c3c run -vvv --linker=builtin --trust=full
cd ../../
echo "Init a library & a project"
./build/c3c init-lib mylib
ls mylib.c3l
./build/c3c init myproject
ls myproject
echo "run compiler tests"
cd test
../build/c3c compile-run -O1 src/test_suite_runner.c3 -- ../build/c3c test_suite/
cd ..
- name: bundle_output
run: |
mkdir c3
cp -r lib c3
cp msvc_build_libraries.py c3
cp build/c3c c3
cp README.md c3
cp releasenotes.md c3
tar czf c3-netbsd-${{matrix.build_type}}.tar.gz c3
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: c3-netbsd-${{matrix.build_type}}
path: c3-netbsd-${{matrix.build_type}}.tar.gz
release:
runs-on: ubuntu-22.04
needs: [build-msvc, build-linux, build-mac, build-linux-ubuntu22]

View File

@@ -572,6 +572,7 @@ else()
-Wno-unused-function
-Wno-unused-variable
-Wno-unused-parameter
-Wno-char-subscripts
)
target_link_options(c3c PRIVATE -pthread)
endif()

View File

@@ -166,7 +166,7 @@ const bool MEMORY_SANITIZER = $$MEMORY_SANITIZER;
const bool THREAD_SANITIZER = $$THREAD_SANITIZER;
const bool ANY_SANITIZER = ADDRESS_SANITIZER || MEMORY_SANITIZER || THREAD_SANITIZER;
const int LANGUAGE_DEV_VERSION = $$LANGUAGE_DEV_VERSION;
const bool HAS_NATIVE_ERRNO = env::LINUX || env::ANDROID || env::OPENBSD || env::DARWIN || env::WIN32;
const bool HAS_NATIVE_ERRNO = env::LINUX || env::ANDROID || env::OPENBSD || env::DARWIN || env::WIN32 || env::NETBSD;
macro bool os_is_darwin() @const
{

View File

@@ -80,7 +80,7 @@ const CInt SIGCHLD = BSD_FLAVOR_SIG ? 20 : 17;
const bool BSD_FLAVOR_SIG @local = env::DARWIN || env::BSD_FAMILY;
alias Time_t = $typefrom(env::WIN32 ? long.typeid : CLong.typeid);
alias Off_t = $typefrom(env::WIN32 ? int.typeid : usz.typeid);
alias Off_t = $typefrom(env::WIN32 ? int.typeid : isz.typeid);
module libc @if(env::LIBC);
@@ -108,7 +108,7 @@ extern fn CInt ferror(CFile stream);
extern fn CInt fflush(CFile stream);
extern fn CInt fgetc(CFile stream);
extern fn ZString fgets(char* string, CInt n, CFile stream);
extern fn CInt fgetpos(CFile stream, Fpos_t* pos);
extern fn CInt fgetpos(CFile stream, Fpos_t* pos) @if(!env::NETBSD);
extern fn Fd fileno(CFile stream) @if(!env::WIN32);
extern fn CFile fopen(ZString filename, ZString mode);
extern fn CInt fprintf(CFile stream, ZString format, ...);
@@ -119,7 +119,7 @@ extern fn void* free(void*);
extern fn CFile freopen(ZString filename, ZString mode, CFile stream);
extern fn CInt fscanf(CFile stream, ZString format, ...);
extern fn CInt fseek(CFile stream, SeekIndex offset, CInt whence) @if(!env::WIN32);
extern fn CInt fsetpos(CFile stream, Fpos_t* pos);
extern fn CInt fsetpos(CFile stream, Fpos_t* pos) @if(!env::NETBSD);
extern fn SeekIndex ftell(CFile stream) @if(!env::WIN32);
extern fn usz fwrite(void* ptr, usz size, usz nmemb, CFile stream);
extern fn CInt getc(CFile stream);
@@ -127,13 +127,13 @@ extern fn CInt getchar();
extern fn ZString getenv(ZString name);
extern fn ZString gets(char* buffer);
extern fn Tm* gmtime(Time_t* timer);
extern fn Tm* gmtime_r(Time_t* timer, Tm* buf) @if(!env::WIN32);
extern fn Tm* gmtime_r(Time_t* timer, Tm* buf) @if(!env::WIN32 && !env::NETBSD);
extern fn CInt ioctl(CInt fd, ulong request, ...);
extern fn CInt isatty(Fd fd) @if(!env::WIN32);
extern fn CLong labs(CLong x);
extern fn LongDivResult ldiv(CLong number, CLong denom);
extern fn Tm* localtime(Time_t* timer);
extern fn Tm* localtime_r(Time_t* timer, Tm* result) @if(!env::WIN32);
extern fn Tm* localtime_r(Time_t* timer, Tm* result) @if(!env::WIN32 && !env::NETBSD);
extern fn void longjmp(JmpBuf* buffer, CInt value) @if(!env::NETBSD && !env::OPENBSD);
extern fn void* malloc(usz size);
extern fn void* memchr(void* str, CInt c, usz n);
@@ -192,17 +192,17 @@ extern fn CLong strtol(char* str, char** endptr, CInt base);
extern fn CULong strtoul(char* str, char** endptr, CInt base);
extern fn usz strxfrm(char* dest, ZString src, usz n);
extern fn CInt system(ZString str);
extern fn Time_t timegm(Tm* timeptr) @if(!env::WIN32);
extern fn Time_t timegm(Tm* timeptr) @if(!env::WIN32 && !env::NETBSD);
extern fn ZString tmpnam(ZString str);
extern fn CFile tmpfile();
extern fn CInt ungetc(CInt c, CFile stream);
extern fn CInt unsetenv(ZString name);
extern fn CInt unsetenv(ZString name) @if(!env::NETBSD);
extern fn isz write(Fd fd, void* buffer, usz count) @if(!env::WIN32);
extern fn CFile fmemopen(void* ptr, usz size, ZString mode);
extern fn isz getline(char** linep, usz* linecapp, CFile stream);
extern fn CInt timespec_get(TimeSpec* ts, CInt base);
extern fn CInt nanosleep(TimeSpec* req, TimeSpec* remaining);
extern fn CInt nanosleep(TimeSpec* req, TimeSpec* remaining) @if(!env::NETBSD);
extern fn ZString ctime(Time_t* timer);
extern fn Time_t time(Time_t* timer);
@@ -229,6 +229,13 @@ extern fn int _longjmp(void*, int);
macro usz longjmp(void* ptr, CInt i) => _longjmp(ptr, i);
extern fn usz malloc_size(void* ptr);
extern fn void* aligned_alloc(usz align, usz size);
extern fn Tm* gmtime_r(Time_t* timer, Tm* buf) @cname("__gmtime_r50") @if(env::NETBSD);
extern fn Tm* localtime_r(Time_t* timer, Tm* result) @cname("__localtime_r50") @if(env::NETBSD);
extern fn CInt nanosleep(TimeSpec* req, TimeSpec* remaining) @cname("__nanosleep50") @if(env::NETBSD);
extern fn CInt fgetpos(CFile stream, Fpos_t* pos) @cname("__fgetpos50") @if(env::NETBSD);
extern fn CInt fsetpos(CFile stream, Fpos_t* pos) @cname("__fsetpos50") @if(env::NETBSD);
extern fn Time_t timegm(Tm* timeptr) @cname("__timegm50") @if(env::NETBSD);
extern fn CInt unsetenv(ZString name) @cname("__unsetenv13") @if(env::NETBSD);
macro CFile stdin() { return fdopen(0, "r"); }
macro CFile stdout() { return fdopen(1, "w"); }
macro CFile stderr() { return fdopen(2, "w"); }
@@ -469,8 +476,8 @@ const Errno EBADF = 9; // Bad file number
const Errno ECHILD = 10; // No child processes
const Errno EAGAIN @if(env::DARWIN) = 35; // Try again Macos
const Errno EAGAIN @if(!env::DARWIN) = 11; // Try again
const Errno EAGAIN @if(env::DARWIN || env::NETBSD) = 35; // Try again Macos
const Errno EAGAIN @if(!env::DARWIN && !env::NETBSD) = 11; // Try again
const Errno ENOMEM = 12; // Out of memory
const Errno EACCES = 13; // Permission denied
@@ -566,6 +573,73 @@ const Errno EPROTO = 100; // Protocol error
const Errno ETIME = 101; // STREAM ioctl() timeout
const Errno EOPNOTSUPP = 102; // Operation not supported on socket
module libc::errno @if(env::NETBSD);
const Errno EWOULDBLOCK = EAGAIN; // Operation would block
const Errno EDEADLK = 11; // Resource deadlock avoided
const Errno EINPROGRESS = 36; // Operation now in progress
const Errno EALREADY = 37; // Operation already in progress
const Errno ENOTSOCK = 38; // Socket operation on non-socket
const Errno EDESTADDRREQ = 39; // Destination address required
const Errno EMSGSIZE = 40; // Message too long
const Errno EPROTOTYPE = 41; // Protocol wrong type for socket
const Errno ENOPROTOOPT = 42; // Protocol option not available
const Errno EPROTONOSUPPORT = 43; // Protocol not supported
const Errno ESOCKTNOSUPPORT = 44; // Socket type not supported
const Errno EOPNOTSUPP = 45; // Operation not supported
const Errno EPFNOSUPPORT = 46; // Protocol family not supported
const Errno EAFNOSUPPORT = 47; // Address family not supported by protocol family
const Errno EADDRINUSE = 48; // Address already in use
const Errno EADDRNOTAVAIL = 49; // Can't assign requested address
const Errno ENETDOWN = 50; // Network is down
const Errno ENETUNREACH = 51; // Network is unreachable
const Errno ENETRESET = 52; // Network dropped connection on reset
const Errno ECONNABORTED = 53; // Software caused connection abort
const Errno ECONNRESET = 54; // Connection reset by peer
const Errno ENOBUFS = 55; // No buffer space available
const Errno EISCONN = 56; // Socket is already connected
const Errno ENOTCONN = 57; // Socket is not connected
const Errno ESHUTDOWN = 58; // Can't send after socket shutdown
const Errno ETOOMANYREFS = 59; // Too many references: can't splice
const Errno ETIMEDOUT = 60; // Operation timed out
const Errno ECONNREFUSED = 61; // Connection refused
const Errno ELOOP = 62; // Too many levels of symbolic links
const Errno ENAMETOOLONG = 63; // File name too long
const Errno EHOSTDOWN = 64; // Host is down
const Errno EHOSTUNREACH = 65; // No route to host
const Errno ENOTEMPTY = 66; // Directory not empty
const Errno EPROCLIM = 67; // Too many processes
const Errno EUSERS = 68; // Too many users
const Errno EDQUOT = 69; // Disc quota exceeded
const Errno ESTALE = 70; // Stale NFS file handle
const Errno EREMOTE = 71; // Too many levels of remote in path
const Errno EBADRPC = 72; // RPC struct is bad
const Errno ERPCMISMATCH = 73; // RPC version wrong
const Errno EPROGUNAVAIL = 74; // RPC prog. not avail
const Errno EPROGMISMATCH = 75; // Program version wrong
const Errno EPROCUNAVAIL = 76; // Bad procedure for program
const Errno ENOLCK = 77; // No locks available
const Errno ENOSYS = 78; // Function not implemented
const Errno EFTYPE = 79; // Inappropriate file type or format
const Errno EAUTH = 80; // Authentication error
const Errno ENEEDAUTH = 81; // Need authenticator
const Errno EIDRM = 82; // Identifier removed
const Errno ENOMSG = 83; // No message of desired type
const Errno EOVERFLOW = 84; // Value too large to be stored in data type
const Errno EILSEQ = 85; // Illegal byte sequence
const Errno ENOTSUP = 86; // Not supported
const Errno ECANCELED = 87; // Operation canceled
const Errno EBADMSG = 88; // Bad or Corrupt message
const Errno ENODATA = 89; // No message available
const Errno ENOSR = 90; // No STREAM resources
const Errno ENOSTR = 91; // Not a STREAM
const Errno ETIME = 92; // STREAM ioctl timeout
const Errno ENOATTR = 93; // Attribute not found
const Errno EMULTIHOP = 94; // Multihop attempted
const Errno ENOLINK = 95; // Link has been severed
const Errno EPROTO = 96; // Protocol error
const Errno EOWNERDEAD = 97; // Previous owner died
const Errno ENOTRECOVERABLE = 98; // State not recoverable
module libc::errno @if(env::WIN32);
const Errno EDEADLK = 36; // Resource deadlock would occur Win32
const Errno ENAMETOOLONG = 38; // File name too long Win32
@@ -583,7 +657,7 @@ const Errno EINPROGRESS = 112; // Operation now in progress Win32
const Errno EDQUOT = -122; // Quota exceeded, not in Win32
const Errno EWOULDBLOCK = 140; // Operation would block
module libc::errno @if(!env::WIN32 && !env::DARWIN);
module libc::errno @if(!env::WIN32 && !env::DARWIN && !env::NETBSD);
const Errno EDEADLK = 35; // Resource deadlock would occur Linux (others?)
const Errno ENAMETOOLONG = 36; // File name too long Linux (others?)
const Errno ENOTEMPTY = 39; // Directory not empty

View File

@@ -11,10 +11,10 @@ extern fn int* __errno() @if(env::ANDROID);
macro int errno() @if(env::ANDROID) => *__errno();
macro void errno_set(int err) @if(env::ANDROID) => *(__errno()) = err;
// OpenBSD
extern fn int* __errno() @if(env::OPENBSD);
macro int errno() @if(env::OPENBSD) => *__errno();
macro void errno_set(int err) @if(env::OPENBSD) => *(__errno()) = err;
// OpenBSD and NetBSD
extern fn int* __errno() @if(env::OPENBSD || env::NETBSD);
macro int errno() @if(env::OPENBSD || env::NETBSD) => *__errno();
macro void errno_set(int err) @if(env::OPENBSD || env::NETBSD) => *(__errno()) = err;
// Darwin
extern fn int* __error() @if(env::DARWIN);

38
lib/std/libc/os/netbsd.c3 Normal file
View File

@@ -0,0 +1,38 @@
module libc @if(env::NETBSD);
alias Blksize_t = int;
alias Nlink_t = uint;
alias Dev_t = long;
alias Ino_t = ulong;
alias Mode_t = uint;
alias Blkcnt_t = long;
struct Stat
{
Dev_t st_dev;
Mode_t st_mode;
Ino_t st_ino;
Nlink_t st_nlink;
Uid_t st_uid;
Gid_t st_gid;
Dev_t st_rdev;
Time_t st_atime;
long st_atimensec;
Time_t st_mtime;
long st_mtimensec;
Time_t st_ctime;
long st_ctimensec;
Time_t st_birthtime;
long st_birthtimensec;
Off_t st_size;
Blkcnt_t st_blocks;
Blksize_t st_blksize;
uint st_flags;
uint st_gen;
uint[2] st_spare;
}
extern fn CInt stat(ZString path, Stat* stat) @cname("__stat50");
extern fn CInt sysctl(CInt *name, CUInt namelen, void *oldp, usz *oldlenp, void *newp, usz newlen);

View File

@@ -60,7 +60,8 @@ struct Stack_t
}
extern fn CInt sigaltstack(Stack_t* ss, Stack_t* old_ss);
extern fn CInt sigaction(CInt signum, Sigaction *action, Sigaction *oldaction);
extern fn CInt sigaction(CInt signum, Sigaction *action, Sigaction *oldaction) @if(!env::NETBSD);
extern fn CInt sigaction(CInt signum, Sigaction *action, Sigaction *oldaction) @cname("__sigaction_siginfo") @if(env::NETBSD);
module libc::termios @if(env::LIBC &&& env::POSIX);

View File

@@ -1,5 +1,5 @@
module std::net::os;
const bool SUPPORTS_INET = env::LIBC && (env::WIN32 || env::DARWIN || env::LINUX || env::ANDROID || env::OPENBSD);
const bool SUPPORTS_INET = env::LIBC && (env::WIN32 || env::DARWIN || env::LINUX || env::ANDROID || env::OPENBSD || env::NETBSD);
typedef AIFamily = CInt;
typedef AIProtocol = CInt;
@@ -18,7 +18,7 @@ struct AddrInfo
AISockType ai_socktype;
AIProtocol ai_protocol;
Socklen_t ai_addrlen;
struct @if(env::WIN32 || env::DARWIN || env::ANDROID)
struct @if(env::WIN32 || env::DARWIN || env::ANDROID || env::NETBSD)
{
ZString ai_canonname;
SockAddrPtr ai_addr;
@@ -87,7 +87,7 @@ extern fn CInt setsockopt(NativeSocket socket, CInt level, CInt optname, void* o
*>
extern fn CInt getsockopt(NativeSocket socket, CInt level, CInt optname, void* optval, Socklen_t* optlen) @if(SUPPORTS_INET);
module std::net::os @if(!env::LIBC || !(env::WIN32 || env::DARWIN || env::LINUX || env::ANDROID || env::OPENBSD));
module std::net::os @if(!env::LIBC || !(env::WIN32 || env::DARWIN || env::LINUX || env::ANDROID || env::OPENBSD || env::NETBSD));
const AIFamily PLATFORM_AF_INET6 = 0;
const AIFamily PLATFORM_AF_IPX = 0;
@@ -194,4 +194,4 @@ const IPPROTO_IPCOMP = 108;
const IPPROTO_PGM = 113;
const IPPROTO_SCTP = 132;
const IPPROTO_DIVERT = 254;
const IPPROTO_RAW = 255;
const IPPROTO_RAW = 255;

108
lib/std/net/os/netbsd.c3 Normal file
View File

@@ -0,0 +1,108 @@
module std::net::os @if(env::NETBSD);
import libc;
const AIFamily PLATFORM_AF_UNSPEC = 0; // unspecified
const AIFamily PLATFORM_AF_LOCAL = 1; // local to host
const AIFamily PLATFORM_AF_UNIX = PLATFORM_AF_LOCAL; // backward compatibility
const AIFamily PLATFORM_AF_INET = 2; // internetwork: UDP, TCP, etc.
const AIFamily PLATFORM_AF_IMPLINK = 3; // arpanet imp addresses
const AIFamily PLATFORM_AF_PUP = 4; // pup protocols: e.g. BSP
const AIFamily PLATFORM_AF_CHAOS = 5; // mit CHAOS protocols
const AIFamily PLATFORM_AF_NS = 6; // XEROX NS protocols
const AIFamily PLATFORM_AF_ISO = 7; // ISO protocols
const AIFamily PLATFORM_AF_OSI = PLATFORM_AF_ISO;
const AIFamily PLATFORM_AF_ECMA = 8; // european computer manufacturers
const AIFamily PLATFORM_AF_DATAKIT = 9; // datakit protocols
const AIFamily PLATFORM_AF_CCITT = 10; // CCITT protocols, X.25 etc
const AIFamily PLATFORM_AF_SNA = 11; // IBM SNA
const AIFamily PLATFORM_AF_DECNET = 12; // DECnet
const AIFamily PLATFORM_AF_DLI = 13; // DEC Direct data link interface
const AIFamily PLATFORM_AF_LAT = 14; // LAT
const AIFamily PLATFORM_AF_HYLINK = 15; // NSC Hyperchannel
const AIFamily PLATFORM_AF_APPLETALK = 16; // Apple Talk
const AIFamily PLATFORM_AF_OROUTE = 17; // Internal Routing Protocol
const AIFamily PLATFORM_AF_LINK = 18; // Link layer interface
const AIFamily PLATFORM_PSEUDO_AF_XTP = 19; // eXpress Transfer Protocol (no AF)
const AIFamily PLATFORM_AF_COIP = 20; // connection-oriented IP, aka ST II
const AIFamily PLATFORM_AF_CNT = 21; // Computer Network Technology
const AIFamily PLATFORM_PSEUDO_AF_RTIP = 22; // Help Identify RTIP packets
const AIFamily PLATFORM_AF_IPX = 23; // Novell Internet Protocol
const AIFamily PLATFORM_AF_INET6 = 24; // IP version 6
const AIFamily PLATFORM_PSEUDO_AF_PIP = 25; // Help Identify PIP packets
const AIFamily PLATFORM_AF_ISDN = 26; // Integrated Services Digital Networ
const AIFamily PLATFORM_AF_E164 = PLATFORM_AF_ISDN; // CCITT E.164 recommendation
const AIFamily PLATFORM_AF_NATM = 27; // native ATM access
const AIFamily PLATFORM_AF_ARP = 28; // (rev.) addr. res. prot. (RFC 826)
const AIFamily PLATFORM_PSEUDO_AF_KEY = 29; // Internal key management protocol
const AIFamily PLATFORM_PSEUDO_AF_HDRCMPLT = 30; /* Used by BPF to not rewrite hdrs
* in interface output routine */
const AIFamily PLATFORM_AF_BLUETOOTH = 31; // Bluetooth: HCI, SCO, L2CAP, RFCOMM
const AIFamily PLATFORM_AF_IEEE80211 = 32; // IEEE80211
const AIFamily PLATFORM_AF_MPLS = 33; // MultiProtocol Label Switching
const AIFamily PLATFORM_AF_ROUTE = 34; // Internal Routing Protocol
const AIFamily PLATFORM_AF_CAN = 35;
const AIFamily PLATFORM_AF_ETHER = 36;
const AIFamily PLATFORM_AF_MAX = 37;
const int SOL_SOCKET = 0xFFFF;
const int SO_DEBUG = 0x0001; // turn on debugging info recording
const int SO_ACCEPTCONN = 0x0002; // socket has had listen()
const int SO_REUSEADDR = 0x0004; // allow local address reuse
const int SO_KEEPALIVE = 0x0008; // keep connections alive
const int SO_DONTROUTE = 0x0010; // just use interface addresses
const int SO_BROADCAST = 0x0020; // permit sending of broadcast msgs
const int SO_USELOOPBACK = 0x0040; // bypass hardware when possible
const int SO_LINGER = 0x0080; // linger on close if data present
const int SO_OOBINLINE = 0x0100; // leave received OOB data in line
const int SO_REUSEPORT = 0x0200; // allow local address & port reuse
const int SO_NOSIGPIPE = 0x0800; // no SIGPIPE from EPIPE
const int SO_ACCEPTFILTER = 0x1000; // there is an accept filter
const int SO_TIMESTAMP = 0x2000; // timestamp received dgram traffic
const int SO_RERROR = 0x4000; // Keep track of receive errors
// additional
const int SO_SNDBUF = 0x1001; // send buffer size
const int SO_RCVBUF = 0x1002; // receive buffer size
const int SO_SNDLOWAT = 0x1003; // send low-water mark
const int SO_RCVLOWAT = 0x1004; // receive low-water mark
const int SO_ERROR = 0x1007; // get error status and clear
const int SO_TYPE = 0x1008; // get socket type
const int SO_OVERFLOWED = 0x1009; // datagrams: return packets dropped
const int SO_NOHEADER = 0x100a; /* user supplies no header to kernel;
* kernel removes header and supplies
* payload
*/
const int SO_SNDTIMEO = 0x100b; // send timeout
const int SO_RCVTIMEO = 0x100c; // receive timeout
// POLLIN through POLLNVAL are predefined by lib/std/net/os/posix.c3
const CUShort POLLRDNORM = 0x0040;
const CUShort POLLWRNORM = POLLOUT;
const CUShort POLLRDBAND = 0x0080;
const CUShort POLLWRBAND = 0x0100;
const CInt MSG_OOB = 0x0001; // process out-of-band data
const CInt MSG_PEEK = 0x0002; // peek at incoming message
const CInt MSG_DONTROUTE = 0x0004; // send without using routing tables
const CInt MSG_EOR = 0x0008; // data completes record
const CInt MSG_TRUNC = 0x0010; // data discarded before delivery
const CInt MSG_CTRUNC = 0x0020; // control data lost before delivery
const CInt MSG_WAITALL = 0x0040; // wait for full request or error
const CInt MSG_DONTWAIT = 0x0080; // this message should be nonblocking
const CInt MSG_BCAST = 0x0100; // this message was rcvd using link-level brdcst
const CInt MSG_MCAST = 0x0200; // this message was rcvd using link-level mcast
const CInt MSG_NOSIGNAL = 0x0400; // do not generate SIGPIPE on EOF
const CInt MSG_CMSG_CLOEXEC = 0x0800; // close on exec receiving fd
const CInt MSG_NBIO = 0x1000; // use non-blocking I/O
const CInt MSG_WAITFORONE = 0x2000; // recvmmsg() wait for one message
const CInt MSG_NOTIFICATION = 0x4000; // SCTP notification
// socket creation options
const SOCK_CLOEXEC = 0x10000000; // set close on exec on socket
const SOCK_NONBLOCK = 0x20000000; // set non blocking i/o socket
const SOCK_NOSIGPIPE = 0x40000000; // don't send sigpipe
const SOCK_FLAGS_MASK = 0xf0000000; // flags mask
const PLATFORM_O_NONBLOCK = SOCK_NONBLOCK;

View File

@@ -1,7 +1,7 @@
module std::os::posix @if(env::POSIX);
import libc;
extern fn CInt clock_gettime(int type, TimeSpec *time);
extern fn CInt clock_gettime(int type, TimeSpec *time) @cname(env::NETBSD ??? "__clock_gettime50" : "clock_gettime");
module std::os::posix @if(env::OPENBSD);
const CLOCK_REALTIME = 0;

View File

@@ -32,9 +32,9 @@ extern fn ZString getcwd(char* pwd, usz len);
extern fn CInt pipe(CInt[2]* pipes);
extern fn CFile fdopen(CInt fd, ZString mode);
extern fn CInt access(ZString path, CInt mode);
extern fn Posix_dirent* readdir(DIRPtr) @cname("readdir") @if(!USE_DARWIN_INODE64) ;
extern fn DIRPtr opendir(ZString);
extern fn void closedir(DIRPtr);
extern fn Posix_dirent* readdir(DIRPtr) @cname(readdir_cname());
extern fn DIRPtr opendir(ZString) @cname(env::NETBSD ??? "__opendir30" : "opendir");
const DT_UNKNOWN = 0;
const DT_FIFO = 1;
@@ -46,5 +46,12 @@ const DT_LNK = 10;
const DT_SOCK = 12;
const DT_WHT = 14;
const USE_DARWIN_INODE64 = env::DARWIN && env::X86_64;
extern fn Posix_dirent* readdir(DIRPtr) @cname("readdir$INODE64") @if(USE_DARWIN_INODE64);
macro String readdir_cname() @local @const
{
$switch:
$case env::DARWIN && env::X86_64: return "readdir$INODE64";
$case env::NETBSD: return "__readdir30";
$default: return "readdir";
$endswitch
}

View File

@@ -58,7 +58,7 @@ const CInt WUNTRACES = 2;
JmpBuf backtrace_jmpbuf @local;
alias BacktraceFn = fn CInt(void** buffer, CInt size);
extern fn CInt backtrace(void** buffer, CInt size) @if(env::OPENBSD);
extern fn CInt backtrace(void** buffer, CInt size) @if(env::OPENBSD || env::NETBSD);
fn void install_signal_handler(CInt signal, SigActionFunction func)
{
@@ -69,7 +69,7 @@ fn void install_signal_handler(CInt signal, SigActionFunction func)
libc::sigaction(signal, &action, &old);
}
fn CInt backtrace(void** buffer, CInt size) @if(!env::OPENBSD)
fn CInt backtrace(void** buffer, CInt size) @if(!env::OPENBSD && !env::NETBSD)
{
if (size < 1) return 0;
void* handle = libc::dlopen("libc.so.6", libc::RTLD_LAZY|libc::RTLD_NODELETE);

View File

@@ -7,6 +7,7 @@
- Add `--custom-libc` option for custom libc implementations.
- Remove use of LLVMGetGlobalContext for single module compilation.
- Fixed bug where constants would get modified when slicing them. #2660
- Support for NetBSD.
### Fixes
- Regression with npot vector in struct triggering an assert #2219.

View File

@@ -401,6 +401,7 @@ typedef enum
MACOS_X64,
MCU_X86,
MINGW_X64,
NETBSD_AARCH64,
NETBSD_X86,
NETBSD_X64,
OPENBSD_X86,

View File

@@ -1779,6 +1779,7 @@ const char *arch_os_target[ARCH_OS_TARGET_LAST + 1] = {
[MACOS_X64] = "macos-x64",
[MCU_X86] = "mcu-x86",
[MINGW_X64] = "mingw-x64",
[NETBSD_AARCH64] = "netbsd-aarch64",
[NETBSD_X86] = "netbsd-x86",
[NETBSD_X64] = "netbsd-x64",
[OPENBSD_X86] = "openbsd-x86",

View File

@@ -34,6 +34,8 @@ ArchOsTarget default_target = ELF_X64;
#elif defined(__aarch64__) || defined(_M_ARM64)
#if defined(__MACH__)
ArchOsTarget default_target = MACOS_AARCH64;
#elif defined(__NetBSD__)
ArchOsTarget default_target = NETBSD_AARCH64;
#elif defined(__ANDROID__)
ArchOsTarget default_target = ANDROID_AARCH64;
#elif defined(__linux__) && __linux__
@@ -286,6 +288,7 @@ static LinkLibc libc_from_arch_os(ArchOsTarget target)
case MACOS_AARCH64:
case MACOS_X64:
case MINGW_X64:
case NETBSD_AARCH64:
case NETBSD_X86:
case NETBSD_X64:
case OPENBSD_X86:

View File

@@ -186,6 +186,7 @@ const char* DEFAULT_TARGETS[] = {
"linux-x64",
"macos-aarch64",
"macos-x64",
"netbsd-aarch64",
"netbsd-x64",
"openbsd-x64",
"wasm32",

View File

@@ -1208,6 +1208,7 @@ static int jump_buffer_size()
// Godbolt test
return 25;
case FREEBSD_X64:
case NETBSD_AARCH64:
case NETBSD_X64:
case OPENBSD_X64:
REMINDER("Guessing setjmp for platform.");

View File

@@ -295,9 +295,9 @@ static void linker_setup_macos(const char ***args_ref, Linker linker_type)
}
static const char *find_freebsd_crt(void)
static const char *find_bsd_crt(void)
{
if (file_exists("/usr/lib/crt1.o"))
if (file_exists("/usr/lib/crt1.o") || file_exists("/usr/lib/crt0.o"))
{
return "/usr/lib/";
}
@@ -583,7 +583,7 @@ static void linker_setup_android(const char ***args_ref, Linker linker_type, boo
add_plain_arg("-lc");
}
static void linker_setup_freebsd(const char ***args_ref, Linker linker_type, bool is_dylib)
static void linker_setup_bsd(const char ***args_ref, Linker linker_type, bool is_dylib)
{
if (linker_type == LINKER_CC)
{
@@ -602,7 +602,7 @@ static void linker_setup_freebsd(const char ***args_ref, Linker linker_type, boo
if (!link_libc()) return;
const char *crt_dir = find_freebsd_crt();
const char *crt_dir = find_bsd_crt();
if (!crt_dir)
{
error_exit("Failed to find the C runtime at link time.");
@@ -613,22 +613,33 @@ static void linker_setup_freebsd(const char ***args_ref, Linker linker_type, boo
}
if (is_pie_pic(compiler.platform.reloc_model))
{
add_plain_arg("-pie");
if (!is_dylib) add_plain_arg("-pie");
add_concat_file_arg(crt_dir, "crti.o");
if (!is_dylib) add_concat_file_arg(crt_dir, "Scrt1.o");
if (!is_dylib && compiler.platform.os != OS_TYPE_NETBSD)
{
add_concat_file_arg(crt_dir, "Scrt1.o");
}
add_concat_file_arg(crt_dir, "crtbeginS.o");
add_concat_file_arg(crt_dir, "crtendS.o");
}
else
{
const char *crt_o = compiler.platform.os == OS_TYPE_NETBSD ? "crt0.o" : "crt1.o";
add_concat_file_arg(crt_dir, "crti.o");
if (!is_dylib) add_concat_file_arg(crt_dir, "crt1.o");
if (!is_dylib) add_concat_file_arg(crt_dir, crt_o);
add_concat_file_arg(crt_dir, "crtbegin.o");
add_concat_file_arg(crt_dir, "crtend.o");
}
add_concat_file_arg(crt_dir, "crtn.o");
add_concat_quote_arg("-L", crt_dir);
add_plain_arg("--dynamic-linker=/libexec/ld-elf.so.1");
if (compiler.platform.os == OS_TYPE_NETBSD)
{
/* The following two flags are needed to work around ld-elf.so not being able
* to handle more than two PT_LOAD segments. */
add_plain_arg("--no-rosegment");
add_plain_arg("-znorelro");
}
linking_add_link(&compiler.linking, "c");
if (compiler.linking.link_math) linking_add_link(&compiler.linking, "m");
linking_add_link(&compiler.linking, "gcc");
@@ -735,7 +746,7 @@ static bool linker_setup(const char ***args_ref, const char **files_to_link, uns
case OS_TYPE_FREEBSD:
case OS_TYPE_OPENBSD:
case OS_TYPE_NETBSD:
linker_setup_freebsd(args_ref, linker_type, is_dylib);
linker_setup_bsd(args_ref, linker_type, is_dylib);
break;
case OS_TYPE_LINUX:
linker_setup_linux(args_ref, linker_type, is_dylib);

View File

@@ -1197,6 +1197,7 @@ static char *arch_to_target_triple(ArchOsTarget target, LinuxLibc linux_libc)
case MACOS_AARCH64: return "aarch64-apple-macosx";
case ELF_AARCH64: return "aarch64-unknown-elf";
case WINDOWS_AARCH64: return "aarch64-pc-windows-msvc";
case NETBSD_AARCH64: return "aarch64-unknown-netbsd";
case LINUX_RISCV32: return linux_libc == LINUX_LIBC_MUSL ? "riscv32-unknown-linux-musl" : "riscv32-unknown-linux";
case ELF_RISCV32: return "riscv32-unknown-elf";
case LINUX_RISCV64: return linux_libc == LINUX_LIBC_MUSL ? "riscv64-unknown-linux-musl" : "riscv64-unknown-linux";

View File

@@ -255,8 +255,8 @@ fn void fdopen() @test @if(!env::WIN32)
fn void fflush() @test
{
CFile stdin = libc::stdin();
assert(libc::fflush(stdin) == 0);
CFile stdout = libc::stdout();
assert(libc::fflush(stdout) == 0);
}
fn void fgets_fget() @test