Files
sx/examples/ffi-objc-call-10-os-gate.sx
agra 5fad92785e ffi 1.14: #objc_call OS-gating cross-compiles cleanly to Android
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.
2026-05-19 19:00:47 +03:00

44 lines
1.5 KiB
Plaintext

// 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();
}
}