From 59f90d2939d61943e7cdc306b03724900b2e8f85 Mon Sep 17 00:00:00 2001 From: agra Date: Mon, 15 Jun 2026 04:35:52 +0300 Subject: [PATCH] =?UTF-8?q?refactor(ffi-linkage):=20Phase=206.3=20?= =?UTF-8?q?=E2=80=94=20migrate=20std/=20#foreign=E2=86=92extern?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pure source rename across 11 std modules (~60 sites): cli/core/fmt/fs/log/ net/kqueue/process/socket/thread/time/trace. All fn-decl markers — bare '#foreign;', '#foreign libc;'/'#foreign tlib;' (LIB ref), and '#foreign libc "csym";' (LIB+rename) → the same 'extern …' tail (extern carries the identical [LIB] ["csym"] axis). Plus 2 stale comment mentions (fmt/fs). No class forms in std. These modules ARE host-corpus-exercised, so the empty snapshot diff is direct validation. Suite green (647 corpus / 444 unit, 0 failed). --- library/modules/std/cli.sx | 4 ++-- library/modules/std/core.sx | 8 ++++---- library/modules/std/fmt.sx | 2 +- library/modules/std/fs.sx | 24 ++++++++++++------------ library/modules/std/log.sx | 2 +- library/modules/std/net/kqueue.sx | 6 +++--- library/modules/std/process.sx | 14 +++++++------- library/modules/std/socket.sx | 26 +++++++++++++------------- library/modules/std/thread.sx | 24 ++++++++++++------------ library/modules/std/time.sx | 2 +- library/modules/std/trace.sx | 8 ++++---- 11 files changed, 60 insertions(+), 60 deletions(-) diff --git a/library/modules/std/cli.sx b/library/modules/std/cli.sx index e33451b..11f4c6a 100644 --- a/library/modules/std/cli.sx +++ b/library/modules/std/cli.sx @@ -41,8 +41,8 @@ libc :: #library "c"; // `char**` / `int` the process was launched with. Declared as `*i64` / // `*i32` since on 64-bit a `char***` is just a pointer to a pointer-sized // slot. -ns_get_argv :: () -> *i64 #foreign libc "_NSGetArgv"; -ns_get_argc :: () -> *i32 #foreign libc "_NSGetArgc"; +ns_get_argv :: () -> *i64 extern libc "_NSGetArgv"; +ns_get_argc :: () -> *i32 extern libc "_NSGetArgc"; // ===================================================================== // EXIT-CODE & `--json` CONTRACT (F3.3) — the minimal surface `dist` (and diff --git a/library/modules/std/core.sx b/library/modules/std/core.sx index 4f1b4cb..fff1c41 100644 --- a/library/modules/std/core.sx +++ b/library/modules/std/core.sx @@ -15,11 +15,11 @@ align_of :: ($T: Type) -> i64 #builtin; // spellings are NOT declared: the Allocator protocol + the std/mem.sx // helpers are the allocation surface (`free` is the typed slice helper // there). Raw libc escape hatch: `libc_malloc` / `libc_free`. -libc_malloc :: (size: i64) -> *void #foreign libc "malloc"; -libc_free :: (ptr: *void) -> void #foreign libc "free"; +libc_malloc :: (size: i64) -> *void extern libc "malloc"; +libc_free :: (ptr: *void) -> void extern libc "free"; -memcpy :: (dst: *void, src: *void, size: i64) -> *void #foreign libc "memcpy"; -memset :: (dst: *void, val: i64, size: i64) -> void #foreign libc "memset"; +memcpy :: (dst: *void, src: *void, size: i64) -> *void extern libc "memcpy"; +memset :: (dst: *void, val: i64, size: i64) -> void extern libc "memset"; type_of :: (val: $T) -> Type #builtin; type_name :: ($T: Type) -> string #builtin; field_count :: ($T: Type) -> i64 #builtin; diff --git a/library/modules/std/fmt.sx b/library/modules/std/fmt.sx index 16127eb..a45d6bb 100644 --- a/library/modules/std/fmt.sx +++ b/library/modules/std/fmt.sx @@ -177,7 +177,7 @@ substr :: (s: string, start: i64, len: i64) -> string { // ── cstring: the C-boundary string ──────────────────────────────────── // `cstring` is ONE pointer to a null-terminated u8 buffer — C's `char *`. // It carries no length (`cstring_len` walks to the terminator) and -// crosses `#foreign` boundaries verbatim in both directions; `?cstring` +// crosses `extern` boundaries verbatim in both directions; `?cstring` // is the nullable case (null pointer = absent). String LITERALS coerce // to `cstring` implicitly — their bytes are terminated constants; every // other `string` must materialize through `to_cstring`. diff --git a/library/modules/std/fs.sx b/library/modules/std/fs.sx index 42c1565..f2bbcbd 100644 --- a/library/modules/std/fs.sx +++ b/library/modules/std/fs.sx @@ -28,17 +28,17 @@ libc :: #library "c"; // variadic tail. Without that, the mode arg goes to the wrong // register on arm64 and the file ends up with mode 0. -open :: (path: [:0]u8, flags: i32, ..args: []i32) -> i32 #foreign libc; -close :: (fd: i32) -> i32 #foreign libc; -read :: (fd: i32, buf: [*]u8, count: usize) -> isize #foreign libc; -write :: (fd: i32, buf: [*]u8, count: usize) -> isize #foreign libc; -lseek :: (fd: i32, offset: i64, whence: i32) -> i64 #foreign libc; -unlink :: (path: [:0]u8) -> i32 #foreign libc; -rmdir :: (path: [:0]u8) -> i32 #foreign libc; -mkdir :: (path: [:0]u8, mode: u32) -> i32 #foreign libc; -access :: (path: [:0]u8, mode: i32) -> i32 #foreign libc; -chmod :: (path: [:0]u8, mode: u32) -> i32 #foreign libc; -rename :: (oldp: [:0]u8, newp: [:0]u8) -> i32 #foreign libc; +open :: (path: [:0]u8, flags: i32, ..args: []i32) -> i32 extern libc; +close :: (fd: i32) -> i32 extern libc; +read :: (fd: i32, buf: [*]u8, count: usize) -> isize extern libc; +write :: (fd: i32, buf: [*]u8, count: usize) -> isize extern libc; +lseek :: (fd: i32, offset: i64, whence: i32) -> i64 extern libc; +unlink :: (path: [:0]u8) -> i32 extern libc; +rmdir :: (path: [:0]u8) -> i32 extern libc; +mkdir :: (path: [:0]u8, mode: u32) -> i32 extern libc; +access :: (path: [:0]u8, mode: i32) -> i32 extern libc; +chmod :: (path: [:0]u8, mode: u32) -> i32 extern libc; +rename :: (oldp: [:0]u8, newp: [:0]u8) -> i32 extern libc; // macOS POSIX constants. Linux values differ; split into platform- // conditional includes when we gain a Linux host. @@ -101,7 +101,7 @@ File :: struct { // ── High-level file API ───────────────────────────────────────────── // Named `open_file` (not `open`) so they don't shadow libc's `open` -// symbol; the latter is needed for `#foreign libc` to resolve. Same +// symbol; the latter is needed for `extern libc` to resolve. Same // idea for `delete_file`/`delete_dir` vs libc's `unlink`/`rmdir`, // `set_mode` vs libc's `chmod`, etc. diff --git a/library/modules/std/log.sx b/library/modules/std/log.sx index 279fa46..a07e9af 100644 --- a/library/modules/std/log.sx +++ b/library/modules/std/log.sx @@ -15,7 +15,7 @@ libc :: #library "c"; -write :: (fd: i32, buf: [*]u8, count: usize) -> isize #foreign libc; +write :: (fd: i32, buf: [*]u8, count: usize) -> isize extern libc; // Prefix the level, append a newline, write the whole line to stderr. log_emit :: (level: string, msg: string) { diff --git a/library/modules/std/net/kqueue.sx b/library/modules/std/net/kqueue.sx index d19c760..f64647a 100644 --- a/library/modules/std/net/kqueue.sx +++ b/library/modules/std/net/kqueue.sx @@ -32,8 +32,8 @@ KqTimespec :: struct { nsec: i64 = 0; } -kqueue :: () -> i32 #foreign libc; -kevent :: (kq: i32, changelist: *Kevent, nchanges: i32, eventlist: *Kevent, nevents: i32, timeout: *KqTimespec) -> i32 #foreign libc; +kqueue :: () -> i32 extern libc; +kevent :: (kq: i32, changelist: *Kevent, nchanges: i32, eventlist: *Kevent, nevents: i32, timeout: *KqTimespec) -> i32 extern libc; // Filters (darwin) EVFILT_READ :i16: -1; @@ -82,4 +82,4 @@ kq_wait :: (kq: i32, events: *Kevent, cap: i32, timeout_ms: i64) -> i32 { } // errno, bound locally (the std.socket accessor is module-scoped there). -errno_slot_kq :: () -> *i32 #foreign libc "__error"; +errno_slot_kq :: () -> *i32 extern libc "__error"; diff --git a/library/modules/std/process.sx b/library/modules/std/process.sx index a54bd9b..170bcb6 100644 --- a/library/modules/std/process.sx +++ b/library/modules/std/process.sx @@ -20,12 +20,12 @@ libc :: #library "c"; // ── Low-level libc bindings ───────────────────────────────────────── -popen :: (cmd: [:0]u8, mode: [:0]u8) -> *void #foreign libc; -pclose :: (stream: *void) -> i32 #foreign libc; -fread :: (ptr: [*]u8, size: usize, nmemb: usize, stream: *void) -> usize #foreign libc; -feof :: (stream: *void) -> i32 #foreign libc; -getenv :: (name: cstring) -> ?cstring #foreign libc; -system :: (cmd: [:0]u8) -> i32 #foreign libc; +popen :: (cmd: [:0]u8, mode: [:0]u8) -> *void extern libc; +pclose :: (stream: *void) -> i32 extern libc; +fread :: (ptr: [*]u8, size: usize, nmemb: usize, stream: *void) -> usize extern libc; +feof :: (stream: *void) -> i32 extern libc; +getenv :: (name: cstring) -> ?cstring extern libc; +system :: (cmd: [:0]u8) -> i32 extern libc; // ── Public types ───────────────────────────────────────────────────── @@ -122,7 +122,7 @@ find_executable :: (name: [:0]u8) -> ?string { // via `write(2)`, so skipping the stdio flush loses nothing. Binding the // symbol `"exit"` would also collide with this module's own `exit` function // at the link level. -clib_exit :: (code: i32) -> noreturn #foreign libc "_exit"; +clib_exit :: (code: i32) -> noreturn extern libc "_exit"; // Stop the process immediately with exit code `code`. Does NOT unwind: // no `defer` / `onfail` cleanup runs, no error-trace frames are pushed — diff --git a/library/modules/std/socket.sx b/library/modules/std/socket.sx index aa9e397..aac317d 100644 --- a/library/modules/std/socket.sx +++ b/library/modules/std/socket.sx @@ -5,18 +5,18 @@ libc :: #library "c"; // POSIX socket API -socket :: (domain: i32, kind: i32, protocol: i32) -> i32 #foreign libc; -setsockopt :: (fd: i32, level: i32, optname: i32, optval: *i32, optlen: u32) -> i32 #foreign libc; -bind :: (fd: i32, addr: *SockAddr, addrlen: u32) -> i32 #foreign libc; -listen :: (fd: i32, backlog: i32) -> i32 #foreign libc; -accept :: (fd: i32, addr: *SockAddr, addrlen: *u32) -> i32 #foreign libc; -connect :: (fd: i32, addr: *SockAddr, addrlen: u32) -> i32 #foreign libc; -read :: (fd: i32, buf: [*]u8, count: usize) -> isize #foreign libc; -write :: (fd: i32, buf: [*]u8, count: usize) -> isize #foreign libc; -close :: (fd: i32) -> i32 #foreign libc; -shutdown :: (fd: i32, how: i32) -> i32 #foreign libc; -socketpair :: (domain: i32, kind: i32, protocol: i32, fds: *i32) -> i32 #foreign libc; -fcntl :: (fd: i32, cmd: i32, ..args: []i32) -> i32 #foreign libc; +socket :: (domain: i32, kind: i32, protocol: i32) -> i32 extern libc; +setsockopt :: (fd: i32, level: i32, optname: i32, optval: *i32, optlen: u32) -> i32 extern libc; +bind :: (fd: i32, addr: *SockAddr, addrlen: u32) -> i32 extern libc; +listen :: (fd: i32, backlog: i32) -> i32 extern libc; +accept :: (fd: i32, addr: *SockAddr, addrlen: *u32) -> i32 extern libc; +connect :: (fd: i32, addr: *SockAddr, addrlen: u32) -> i32 extern libc; +read :: (fd: i32, buf: [*]u8, count: usize) -> isize extern libc; +write :: (fd: i32, buf: [*]u8, count: usize) -> isize extern libc; +close :: (fd: i32) -> i32 extern libc; +shutdown :: (fd: i32, how: i32) -> i32 extern libc; +socketpair :: (domain: i32, kind: i32, protocol: i32, fds: *i32) -> i32 extern libc; +fcntl :: (fd: i32, cmd: i32, ..args: []i32) -> i32 extern libc; // Constants (macOS) AF_UNIX :i32: 1; @@ -49,7 +49,7 @@ htons :: (port: i64) -> u16 { // errno resolves to a real function under the C macro: `__error` on // darwin, `__errno_location` on linux (C3 selects per-OS). -errno_slot :: () -> *i32 #foreign libc "__error"; +errno_slot :: () -> *i32 extern libc "__error"; // fcntl file-status flags + errno values (macOS). F_GETFL :i32: 3; diff --git a/library/modules/std/thread.sx b/library/modules/std/thread.sx index 727d340..6752da6 100644 --- a/library/modules/std/thread.sx +++ b/library/modules/std/thread.sx @@ -26,20 +26,20 @@ tlib :: #library "c"; -pthread_create :: (thread: *usize, attr: *void, start: (*void) -> *void callconv(.c), arg: *void) -> i32 #foreign tlib; -pthread_join :: (thread: usize, retval: **void) -> i32 #foreign tlib; -pthread_detach :: (thread: usize) -> i32 #foreign tlib; +pthread_create :: (thread: *usize, attr: *void, start: (*void) -> *void callconv(.c), arg: *void) -> i32 extern tlib; +pthread_join :: (thread: usize, retval: **void) -> i32 extern tlib; +pthread_detach :: (thread: usize) -> i32 extern tlib; -pthread_mutex_init :: (m: *MutexBuf, attr: *void) -> i32 #foreign tlib; -pthread_mutex_lock :: (m: *MutexBuf) -> i32 #foreign tlib; -pthread_mutex_unlock :: (m: *MutexBuf) -> i32 #foreign tlib; -pthread_mutex_destroy :: (m: *MutexBuf) -> i32 #foreign tlib; +pthread_mutex_init :: (m: *MutexBuf, attr: *void) -> i32 extern tlib; +pthread_mutex_lock :: (m: *MutexBuf) -> i32 extern tlib; +pthread_mutex_unlock :: (m: *MutexBuf) -> i32 extern tlib; +pthread_mutex_destroy :: (m: *MutexBuf) -> i32 extern tlib; -pthread_cond_init :: (c: *CondBuf, attr: *void) -> i32 #foreign tlib; -pthread_cond_wait :: (c: *CondBuf, m: *MutexBuf) -> i32 #foreign tlib; -pthread_cond_signal :: (c: *CondBuf) -> i32 #foreign tlib; -pthread_cond_broadcast :: (c: *CondBuf) -> i32 #foreign tlib; -pthread_cond_destroy :: (c: *CondBuf) -> i32 #foreign tlib; +pthread_cond_init :: (c: *CondBuf, attr: *void) -> i32 extern tlib; +pthread_cond_wait :: (c: *CondBuf, m: *MutexBuf) -> i32 extern tlib; +pthread_cond_signal :: (c: *CondBuf) -> i32 extern tlib; +pthread_cond_broadcast :: (c: *CondBuf) -> i32 extern tlib; +pthread_cond_destroy :: (c: *CondBuf) -> i32 extern tlib; // darwin pthread_mutex_t: { long __sig; char __opaque[56]; } — 64 bytes. MutexBuf :: struct { diff --git a/library/modules/std/time.sx b/library/modules/std/time.sx index 292e64e..929a306 100644 --- a/library/modules/std/time.sx +++ b/library/modules/std/time.sx @@ -24,7 +24,7 @@ Timespec :: struct { nsec: i64; } -clock_gettime :: (clock_id: i32, ts: *Timespec) -> i32 #foreign libc; +clock_gettime :: (clock_id: i32, ts: *Timespec) -> i32 extern libc; CLOCK_REALTIME :i32: 0; CLOCK_MONOTONIC :i32: 6; // darwin; linux is 1 (C3 selects per-OS) diff --git a/library/modules/std/trace.sx b/library/modules/std/trace.sx index e92e213..641e733 100644 --- a/library/modules/std/trace.sx +++ b/library/modules/std/trace.sx @@ -50,11 +50,11 @@ spaces :: (n: i32) -> string { // `frame_at` returns the raw stored `u64`; `__trace_resolve_frame` turns it // into a `TraceFrame` — by reinterpreting the stamped `*TraceFrame` in compiled code, or // by resolving the packed `(func_id, span.start)` in the comptime interpreter. -sx_trace_len :: () -> u32 #foreign; -sx_trace_truncated :: () -> u32 #foreign; -sx_trace_frame_at :: (i: u32) -> u64 #foreign; +sx_trace_len :: () -> u32 extern; +sx_trace_truncated :: () -> u32 extern; +sx_trace_frame_at :: (i: u32) -> u64 extern; -write :: (fd: i32, buf: [*]u8, count: usize) -> isize #foreign libc; +write :: (fd: i32, buf: [*]u8, count: usize) -> isize extern libc; // Render the current trace buffer to a string (allocated from // context.allocator). Empty buffer → "" so callers can cheaply skip output.