docs(ffi-linkage): document extern/export linkage keywords (Phase 4)

This commit is contained in:
agra
2026-06-14 15:40:37 +03:00
parent 4101cbc3e7
commit a8e0a8961b
2 changed files with 46 additions and 0 deletions

View File

@@ -409,6 +409,18 @@ printf :: (fmt: [:0]u8, args: ..Any) -> i32 #foreign libc;
write_fd :: (fd: i32, buf: [*]u8, count: u64) -> i64 #foreign libc "write";
```
`extern` / `export` are the keyword surface for C linkage. `extern` is the modern
spelling of `#foreign` (import); `export` is its dual — define a function in sx and
expose it under the C ABI so C can call back in. Both imply `callconv(.c)` and take
the same optional `[LIB] ["csym"]` rename tail; they also apply to data globals and
to Obj-C / JNI runtime-class aggregates (postfix after the `#objc_class(…)` directive).
```sx
abs :: (x: i32) -> i32 extern; // import (== `#foreign`)
sx_square :: (x: i32) -> i32 export { x * x } // define + expose to C
__stdinp : *void extern; // extern data global
NSObject :: #objc_class("NSObject") extern { alloc :: () -> *NSObject; } // reference a runtime class
```
Direct C header import:
```sx
#import c {

View File

@@ -1209,6 +1209,40 @@ write_fd :: (fd: i32, buf: [*]u8, count: u64) -> i64 #foreign libc "write";
- `#foreign lib_ref` declares a function as external C. The library reference is optional: when present it is passed to the linker (`-lname` on Unix); when omitted (`name :: (…) -> T #foreign;`), the symbol must resolve at link time from a framework or an already-linked / auto-detected library.
- `#foreign lib_ref "c_symbol"` renames the binding: the sx function name differs from the C symbol. This avoids name collisions (e.g. POSIX `write` vs an sx builtin).
#### `extern` / `export` linkage keywords
`extern` and `export` are the keyword surface for C linkage. `extern` is the
modern spelling of `#foreign` (import a symbol defined elsewhere); `export` is
its dual — **define** a symbol in sx and expose it under the C ABI so C (or asm,
or another language) can call it. Both imply `callconv(.c)`, carry external
linkage, and suppress the implicit sx context parameter. They are postfix
modifiers, written where `callconv` would go.
```sx
// Functions — `extern` imports, `export` defines + exposes
abs :: (x: i32) -> i32 extern; // import (== `#foreign`)
write_fd :: (fd: i32, buf: [*]u8, n: u64) -> i64 extern libc "write"; // [LIB] ["csym"]
sx_square :: (x: i32) -> i32 export { x * x } // define; C can call `sx_square`
triple_c :: (x: i32) -> i32 export "triple_c" { x * 3 } // export under a C name
// Data globals — `extern` imports an external global
__stdinp : *void extern; // (== `<name> : <type> #foreign;`)
// Aggregates (Obj-C / JNI runtime classes) — postfix after the directive
NSObject :: #objc_class("NSObject") extern { alloc :: () -> *NSObject; } // reference
SxFoo :: #objc_class("SxFoo") export { counter: i32; bump :: (self: *Self) { … } } // define
```
- `extern` takes the same optional `[LIB] ["csym"]` tail as `#foreign`
(`extern libc "write"`): a `#library` alias reference then a C symbol rename.
The `#library` declaration + build-flag linking mechanism is a separate axis —
`extern` *references* a library, it does not declare one.
- `export "csym"` renames the exported symbol the same way (the C-visible name
differs from the sx name).
- On an aggregate, the prefix `#foreign` modifier and a postfix `extern`/`export`
keyword are the same axis and cannot be combined: `#objc_class("X") extern` is
exactly `#foreign #objc_class("X")`; writing both is a compile error.
### C Interop Type Mapping
| C type | sx type | Notes |