Goal
Let Aether produce a linkable iOS library — a .a/.dylib of aether_<name> C-ABI exports built for aarch64-ios (device) and the iOS simulator — so an iOS app (Swift/Obj-C shell, driven by Xcode) can delegate its logic to Aether. This is the prerequisite for running the aether-ui DSL on iOS via a UIKit backend (companion request: aether-lang-dev/aether-ui — "UIKit backend for iOS").
Scope note: on iOS there is no standalone-executable story (no exec, no daemons, App Store sandbox). Aether's realistic role is library provider; the app shell + Info.plist + code-signing + bundling stay in Xcode. Aether's AOT-to-C model is actually a good fit here — no JIT / no writable-executable memory, which iOS forbids anyway.
What's already true (so this is bounded)
- The zig cross backend (
tools/ae_cross.c) already emits aarch64-macos / x86_64-macos (Tier A, self-contained) and has a Tier-B pattern (FreeBSD) for targets whose SDK zig does NOT bundle — those require an external sysroot via AETHER_SYSROOT (cross_target_needs_sysroot()).
- The runtime already targets the Darwin/XNU substrate iOS shares with macOS: kqueue poller (
runtime/scheduler/aether_io_poller_kqueue.c), pthreads, Mach. Most of the runtime should compile for iOS unchanged.
--emit=lib already produces the aether_<name> alias-stub + catalog ABI consumed today by Python/ctypes, Java/Panama, Ruby/Fiddle — Swift/Obj-C is just another FFI caller.
Work items
- Target triples — add
aarch64-ios → zig aarch64-ios, plus simulator targets aarch64-ios-simulator and x86_64-ios-simulator → the zig -ios-simulator triples. zig supports these but does not bundle the iOS SDK, so mark them Tier B: cross_target_needs_sysroot() returns true and they require AETHER_SYSROOT pointing at the Xcode iPhoneOS.sdk / iPhoneSimulator.sdk. Mirrors the existing FreeBSD-sysroot machinery (see aether-crossbuild's fetch-freebsd-base.sh for the pattern).
- Mach-O min-version / platform load commands — iOS objects need the correct
platform/minos set (device vs simulator differ). Ensure the zig cc invocation passes the right -target/-mios-version-min= (or the sysroot-implied) flags so the produced archive links into an iOS app without "building for iOS but linking object built for macOS" errors.
- Stub App-Store-forbidden syscalls on iOS —
std.os uses fork/exec/posix_spawn (run_capture, exec, spawn, the sandbox spawners in runtime/sandbox/). iOS bans child processes, so these must compile to "unsupported on iOS" stubs (the existing stub-not-fake degrade convention), gated on TARGET_OS_IPHONE (from <TargetConditionals.h>). The LD_PRELOAD sandbox (libaether_sandbox_preload) is inert on iOS (no LD_PRELOAD) — fine, iOS is the sandbox. Networking: client is fine; listening servers / some socket opts are restricted — degrade std.http.server accordingly or document the limit.
- Audit the
__APPLE__ guards — several cover macOS-only APIs (getmntinfo, some sysctl, menu/window bits) that differ or are absent on iOS. Split iOS from macOS inside those blocks with TARGET_OS_IPHONE. (~34 __APPLE__ sites in runtime+std; a code audit, not a rewrite.)
- CI / smoke test — a macOS-runner lane (Xcode present) that cross-builds the
.a for the simulator and links it into a tiny throwaway Xcode app run in the iOS simulator. Comparable to the existing FreeBSD-crossbuild lane. Device builds need signing → out of CI scope initially.
Milestones
- M1 (this issue's core):
ae build --emit=lib --target aarch64-ios-simulator prog.ae produces an archive that links + runs inside a minimal simulator app; spawn/sandbox APIs stubbed. Device target (aarch64-ios) builds too (signing left to the consumer's Xcode project).
- M2 (separate, aether-ui): the UIKit backend so the whole app including UI is Aether. Tracked in aether-lang-dev/aether-ui.
Acceptance
--emit=lib --target aarch64-ios[-simulator] yields an archive that (a) links into an Xcode app target and (b) runs its aether_<name> exports in the iOS simulator, with fork/exec/spawn cleanly reporting "unsupported on iOS" rather than failing to link.
Explicitly out of scope
Compiler-emitted .app bundles, Info.plist generation, and code-signing — those stay in Xcode. Standalone iOS executables / daemons / listening servers — not possible under App Store rules regardless of effort.
Goal
Let Aether produce a linkable iOS library — a
.a/.dylibofaether_<name>C-ABI exports built foraarch64-ios(device) and the iOS simulator — so an iOS app (Swift/Obj-C shell, driven by Xcode) can delegate its logic to Aether. This is the prerequisite for running theaether-uiDSL on iOS via a UIKit backend (companion request: aether-lang-dev/aether-ui — "UIKit backend for iOS").Scope note: on iOS there is no standalone-executable story (no
exec, no daemons, App Store sandbox). Aether's realistic role is library provider; the app shell +Info.plist+ code-signing + bundling stay in Xcode. Aether's AOT-to-C model is actually a good fit here — no JIT / no writable-executable memory, which iOS forbids anyway.What's already true (so this is bounded)
tools/ae_cross.c) already emitsaarch64-macos/x86_64-macos(Tier A, self-contained) and has a Tier-B pattern (FreeBSD) for targets whose SDK zig does NOT bundle — those require an external sysroot viaAETHER_SYSROOT(cross_target_needs_sysroot()).runtime/scheduler/aether_io_poller_kqueue.c), pthreads, Mach. Most of the runtime should compile for iOS unchanged.--emit=libalready produces theaether_<name>alias-stub + catalog ABI consumed today by Python/ctypes, Java/Panama, Ruby/Fiddle — Swift/Obj-C is just another FFI caller.Work items
aarch64-ios→ zigaarch64-ios, plus simulator targetsaarch64-ios-simulatorandx86_64-ios-simulator→ the zig-ios-simulatortriples. zig supports these but does not bundle the iOS SDK, so mark them Tier B:cross_target_needs_sysroot()returns true and they requireAETHER_SYSROOTpointing at the XcodeiPhoneOS.sdk/iPhoneSimulator.sdk. Mirrors the existing FreeBSD-sysroot machinery (see aether-crossbuild'sfetch-freebsd-base.shfor the pattern).platform/minosset (device vs simulator differ). Ensure the zig cc invocation passes the right-target/-mios-version-min=(or the sysroot-implied) flags so the produced archive links into an iOS app without "building for iOS but linking object built for macOS" errors.std.osusesfork/exec/posix_spawn(run_capture,exec, spawn, the sandbox spawners inruntime/sandbox/). iOS bans child processes, so these must compile to "unsupported on iOS" stubs (the existing stub-not-fake degrade convention), gated onTARGET_OS_IPHONE(from<TargetConditionals.h>). TheLD_PRELOADsandbox (libaether_sandbox_preload) is inert on iOS (no LD_PRELOAD) — fine, iOS is the sandbox. Networking: client is fine; listening servers / some socket opts are restricted — degradestd.http.serveraccordingly or document the limit.__APPLE__guards — several cover macOS-only APIs (getmntinfo, somesysctl, menu/window bits) that differ or are absent on iOS. Split iOS from macOS inside those blocks withTARGET_OS_IPHONE. (~34__APPLE__sites in runtime+std; a code audit, not a rewrite.).afor the simulator and links it into a tiny throwaway Xcode app run in the iOS simulator. Comparable to the existing FreeBSD-crossbuild lane. Device builds need signing → out of CI scope initially.Milestones
ae build --emit=lib --target aarch64-ios-simulator prog.aeproduces an archive that links + runs inside a minimal simulator app; spawn/sandbox APIs stubbed. Device target (aarch64-ios) builds too (signing left to the consumer's Xcode project).Acceptance
--emit=lib --target aarch64-ios[-simulator]yields an archive that (a) links into an Xcode app target and (b) runs itsaether_<name>exports in the iOS simulator, withfork/exec/spawn cleanly reporting "unsupported on iOS" rather than failing to link.Explicitly out of scope
Compiler-emitted
.appbundles,Info.plistgeneration, and code-signing — those stay in Xcode. Standalone iOS executables / daemons / listening servers — not possible under App Store rules regardless of effort.