stdlib: relocate modules under library/
- examples/modules/ -> library/modules/ (top-level, no more symlink hacks in consumer projects) - compiler discovers stdlib via _NSGetExecutablePath / readlink /proc/self/exe; searches dev layout (../../library), install layout (../library), and alongside-binary fallback - SX_STDLIB_PATH env var overrides for tests / dev convenience - SX_DEBUG_STDLIB env var dumps the discovery results - build.zig installs library/ alongside the binary - Compilation gains stdlib_paths field threaded through resolveImports - 50 tests pass; consumer projects can now build from any cwd
This commit is contained in:
75
library/modules/std/objc.sx
Normal file
75
library/modules/std/objc.sx
Normal file
@@ -0,0 +1,75 @@
|
||||
// Obj-C runtime FFI primitives.
|
||||
//
|
||||
// `*void` stands in for the Obj-C `id`/`Class`/`SEL` types. There's no
|
||||
// sx-level type alias yet, so naming discipline at call sites is the only
|
||||
// thing keeping them apart.
|
||||
//
|
||||
// objc_msgSend has the standard ARM64 calling convention (no varargs path).
|
||||
// Each call site must invoke through a function pointer of the *exact*
|
||||
// argument and return shape. The idiom:
|
||||
//
|
||||
// msg_fn : (recv: *void, sel: *void, arg: [*]u8) -> *void = xx objc_msgSend;
|
||||
// result := msg_fn(receiver, selector, c_string);
|
||||
|
||||
// On macOS libobjc is auto-loaded by libSystem; on iOS it isn't, so we
|
||||
// link it explicitly. Foundation registers NSString etc. with the runtime,
|
||||
// also auto-loaded on macOS and required as an explicit framework on iOS.
|
||||
objc :: #library "objc";
|
||||
#framework "Foundation";
|
||||
|
||||
objc_getClass :: (name: [*]u8) -> *void #foreign objc;
|
||||
objc_lookUpClass :: (name: [*]u8) -> *void #foreign objc;
|
||||
sel_registerName :: (name: [*]u8) -> *void #foreign objc;
|
||||
class_createInstance :: (cls: *void, extra: usize) -> *void #foreign objc;
|
||||
object_getClass :: (obj: *void) -> *void #foreign objc;
|
||||
|
||||
// Declared with the simplest non-variadic shape. Cast per call site.
|
||||
objc_msgSend :: (recv: *void, sel: *void) -> *void #foreign objc;
|
||||
|
||||
// ─── Dynamic class registration ─────────────────────────────────────────
|
||||
// Define a new Obj-C class at runtime: allocate the pair, attach methods +
|
||||
// protocols, then finalize with `objc_registerClassPair`. The class is then
|
||||
// usable via `class_createInstance` and Obj-C dispatch.
|
||||
//
|
||||
// IMPs (method implementations) are function pointers with the implicit
|
||||
// Obj-C method shape: `(self: *void, _cmd: *void, ...args) -> ret` with
|
||||
// `callconv(.c)` so they land args in the standard C registers.
|
||||
//
|
||||
// Method type encoding strings follow Apple's runtime DSL:
|
||||
// v = void c = char/BOOL i = int l = long f = float d = double
|
||||
// @ = id (object) : = SEL # = Class
|
||||
// Return type comes first, then receiver (`@`), then `_cmd` (`:`), then args.
|
||||
// Examples:
|
||||
// "v@:" -> void method(id, SEL)
|
||||
// "c@:" -> BOOL method(id, SEL)
|
||||
// "@@:@" -> id method(id, SEL, id)
|
||||
// "B@:@@" -> BOOL method(id, SEL, id, id)
|
||||
objc_allocateClassPair :: (super: *void, name: [*]u8, extra: usize) -> *void #foreign objc;
|
||||
class_addMethod :: (cls: *void, sel: *void, imp: *void, types: [*]u8) -> bool #foreign objc;
|
||||
class_addProtocol :: (cls: *void, proto: *void) -> bool #foreign objc;
|
||||
objc_getProtocol :: (name: [*]u8) -> *void #foreign objc;
|
||||
objc_registerClassPair :: (cls: *void) -> void #foreign objc;
|
||||
|
||||
// Foundation C-API helpers (Foundation is already linked above via #framework).
|
||||
// NSLog takes an NSString format; the variadic tail is not exposed here.
|
||||
NSLog :: (fmt: *void) #foreign;
|
||||
|
||||
// ─── Convenience helpers ────────────────────────────────────────────────
|
||||
// These hide the typed-fn-pointer cast for the most common shapes. They
|
||||
// re-register selectors per call — if you're in a tight loop, cache the SEL.
|
||||
|
||||
// Wrap a C string in an autoreleased NSString.
|
||||
ns_string :: (s: [*]u8) -> *void {
|
||||
cls := objc_getClass("NSString".ptr);
|
||||
sel := sel_registerName("stringWithUTF8String:".ptr);
|
||||
fn_ptr : (*void, *void, [*]u8) -> *void = xx objc_msgSend;
|
||||
return fn_ptr(cls, sel, s);
|
||||
}
|
||||
|
||||
// View an NSString's bytes as a C string. The returned pointer's lifetime is
|
||||
// tied to the NSString; don't free it.
|
||||
c_string :: (ns: *void) -> [*]u8 {
|
||||
sel := sel_registerName("UTF8String".ptr);
|
||||
fn_ptr : (*void, *void) -> [*]u8 = xx objc_msgSend;
|
||||
return fn_ptr(ns, sel);
|
||||
}
|
||||
17
library/modules/std/uikit.sx
Normal file
17
library/modules/std/uikit.sx
Normal file
@@ -0,0 +1,17 @@
|
||||
// UIKit framework bindings — iOS only.
|
||||
//
|
||||
// Consumers `#import "modules/std/uikit.sx";` and inherit the
|
||||
// `#framework "UIKit"` link directive plus any C-API declarations exposed
|
||||
// here. Obj-C class/method dispatch goes through `modules/std/objc.sx`
|
||||
// which we re-import so users only need this one file.
|
||||
|
||||
#import "objc.sx";
|
||||
|
||||
#framework "UIKit";
|
||||
|
||||
// int UIApplicationMain(int argc, char *_Nullable argv[_Nonnull],
|
||||
// NSString *_Nullable principalClassName,
|
||||
// NSString *_Nullable delegateClassName);
|
||||
//
|
||||
// Blocks. Drives the iOS run loop. Normally never returns.
|
||||
UIApplicationMain :: (argc: s32, argv: *void, principal_class: *void, delegate_class: *void) -> s32 #foreign;
|
||||
Reference in New Issue
Block a user