From 5fad92785e792e660719ebec117191238eb29a15 Mon Sep 17 00:00:00 2001 From: agra Date: Tue, 19 May 2026 19:00:47 +0300 Subject: [PATCH] ffi 1.14: #objc_call OS-gating cross-compiles cleanly to Android MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 109/109 host tests pass; tests/cross_compile.sh's first real tuple (`android | examples/ffi-objc-call-10-os-gate.sx`) compiles through `sx build --target android` without finding any `@objc_msgSend` / `@sel_registerName` symbols in the output — the `inline if OS == .ios { #objc_call(...) }` arm is stripped at sx compile time before emit_llvm runs, so the Android toolchain (Bionic + libGLESv3 / NDK linker) doesn't see the Obj-C runtime references that would otherwise be undefined. Host (macOS): the example prints "host stripped both" — the iOS arm is stripped (we're not iOS) AND the Android arm is stripped (we're not Android), confirming `inline if OS == { case }` symmetric strip-and-render works around `#objc_call` sites. The example carries a 3-line `android_main` trampoline so the NDK linker's `-u ANativeActivity_onCreate` / entry-point discovery is satisfied — pattern shared with chess + the other android examples. --- examples/ffi-objc-call-10-os-gate.sx | 43 ++++++++++++++++++++ tests/cross_compile.sh | 9 ++-- tests/expected/ffi-objc-call-10-os-gate.exit | 1 + tests/expected/ffi-objc-call-10-os-gate.txt | 1 + 4 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 examples/ffi-objc-call-10-os-gate.sx create mode 100644 tests/expected/ffi-objc-call-10-os-gate.exit create mode 100644 tests/expected/ffi-objc-call-10-os-gate.txt diff --git a/examples/ffi-objc-call-10-os-gate.sx b/examples/ffi-objc-call-10-os-gate.sx new file mode 100644 index 0000000..1ce16dc --- /dev/null +++ b/examples/ffi-objc-call-10-os-gate.sx @@ -0,0 +1,43 @@ +// Phase 1 step 1.14 (PLAN-FFI.md): `#objc_call` inside an +// `inline if OS == .ios { ... }` arm cross-compiles cleanly to +// Android. The comptime gate must strip the arm BEFORE the +// `objc_msg_send` lowering runs, otherwise emit_llvm would +// produce calls to `@objc_msgSend` / `@sel_registerName` that +// don't exist in Bionic + libGLESv3 / linker would fail. +// +// On macOS the iOS arm is also stripped (we're not iOS) so the +// runtime test just prints "host stripped both", proving the +// `inline if OS == { case }` form works around `#objc_call` +// sites the same way it does elsewhere. + +#import "modules/std.sx"; +#import "modules/compiler.sx"; + +main :: () -> s32 { + inline if OS == { + case .ios: { + // Stripped on macOS + Android. Compiled on iOS / ios-sim. + #objc_call(void)(null, "init"); + print("ios path\n"); + } + case .android: { + // Stripped on macOS + iOS. Compiled on Android. + // Nothing #objc_call-shaped here — just text — so we + // exercise the gate symmetrically across targets. + print("android path\n"); + } + else: { + print("host stripped both\n"); + } + } + 0; +} + +// Android target requires `android_main` as the NDK entry — kept as +// a 3-line trampoline so this example can pass through +// `--target android` builds in `tests/cross_compile.sh`. +android_main :: (app: *void) { + inline if OS == .android { + main(); + } +} diff --git a/tests/cross_compile.sh b/tests/cross_compile.sh index 4cd6a4b..559a07f 100755 --- a/tests/cross_compile.sh +++ b/tests/cross_compile.sh @@ -22,9 +22,12 @@ TMP_DIR="${TMPDIR:-/tmp}/sx-cross-compile" mkdir -p "$TMP_DIR" # Tuple format: "|" -# Add entries as cross-only examples land. Empty for now — Phase 0 only -# lays down the runner; baselines live in tests/run_examples.sh territory. -TUPLES=() +# Add entries as cross-only examples land. Verifies the example +# compiles cleanly for the target's NDK / SDK without needing the +# host to actually run it. +TUPLES=( + "android|examples/ffi-objc-call-10-os-gate.sx" +) PASS=0 FAIL=0 diff --git a/tests/expected/ffi-objc-call-10-os-gate.exit b/tests/expected/ffi-objc-call-10-os-gate.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/expected/ffi-objc-call-10-os-gate.exit @@ -0,0 +1 @@ +0 diff --git a/tests/expected/ffi-objc-call-10-os-gate.txt b/tests/expected/ffi-objc-call-10-os-gate.txt new file mode 100644 index 0000000..c17ab89 --- /dev/null +++ b/tests/expected/ffi-objc-call-10-os-gate.txt @@ -0,0 +1 @@ +host stripped both