android: Platform-owned entry bridge + .android OS enum variant
User writes BOTH `main` and a 3-line `android_main(app)` trampoline.
The library provides `sx_android_bootstrap(app)` (stashes the NDK app
pointer into a platform-owned global) and `AndroidPlatform` impl of
the Platform protocol. The library NEVER references `main` — the OS-
shape entry symbol lives in user code where the other entry symbols
already live. iOS / SDL3 keep their existing shape; only Android adds
the trampoline.
Cross-cutting bits this commit ships:
library/modules/compiler.sx
Add `android` variant to `OperatingSystem`.
src/ir/lower.zig
- injectComptimeConstants: map TargetConfig.isAndroid() → .android.
- New Pass 4 `checkRequiredEntryPoints`: emit a clean diagnostic
when `--target android` is requested but `android_main` isn't
defined, instead of letting the user crash on a dlopen-time
missing-symbol error.
library/modules/platform/android.sx
AndroidPlatform impl of the Platform protocol — EGL bringup on
`APP_CMD_INIT_WINDOW`, ALooper(0) polling, dispatches the user's
frame closure each ~16 ms tick. `sx_android_bootstrap(app)` is the
only function exposed for the entry trampoline.
examples/99-android-egl-clear.sx
Rewritten to use the new pattern: minimum `main` + `android_main`
pair, AndroidPlatform-driven render loop. Doubles as the usage
reference users hand off to the compiler diagnostic.
Verified on Pixel 7 Pro: purple clear-color frame, periodic
`rendered 60 frames` logcat lines. iOS-sim chess + 86/86 regression
tests pass.
This commit is contained in:
@@ -207,6 +207,39 @@ pub const Lowering = struct {
|
||||
self.lowerMainAndComptime(decls);
|
||||
// Pass 3: lower deferred functions (any_to_string etc.) now that all types are registered
|
||||
self.lowerDeferredTypeFns();
|
||||
// Pass 4: target-specific entry-point sanity checks
|
||||
self.checkRequiredEntryPoints();
|
||||
}
|
||||
|
||||
/// On Android, the OS loader calls `android_main(app: *void)` — there's
|
||||
/// no `main()` invocation from the system. If the user hasn't defined
|
||||
/// `android_main`, native_app_glue can't find it at runtime and the
|
||||
/// activity dies with an unhelpful "library doesn't export
|
||||
/// `android_main`" error after the .so is loaded. Catch this at
|
||||
/// compile time with a clear hint pointing at the platform module
|
||||
/// that provides the helper.
|
||||
fn checkRequiredEntryPoints(self: *Lowering) void {
|
||||
const tc = self.target_config orelse return;
|
||||
if (!tc.isAndroid()) return;
|
||||
|
||||
const wanted = self.module.types.internString("android_main");
|
||||
var has_defn = false;
|
||||
for (self.module.functions.items) |func| {
|
||||
if (func.name != wanted) continue;
|
||||
if (func.is_extern) continue;
|
||||
if (func.blocks.items.len == 0) continue;
|
||||
has_defn = true;
|
||||
break;
|
||||
}
|
||||
if (has_defn) return;
|
||||
if (self.diagnostics) |diags| {
|
||||
diags.addFmt(.err, null,
|
||||
"target is Android but no `android_main` function defined. " ++
|
||||
"The OS calls `android_main(app: *void)` as the entry point — " ++
|
||||
"add it to your main.sx (it can be a 3-line trampoline that " ++
|
||||
"calls `sx_android_bootstrap(app)` then `main()` — see " ++
|
||||
"`examples/99-android-egl-clear.sx`).", .{});
|
||||
}
|
||||
}
|
||||
|
||||
/// Inject compile-time constants from target_config into comptime_constants.
|
||||
@@ -223,6 +256,8 @@ pub const Lowering = struct {
|
||||
self.findVariantIndex(os_info.@"enum".variants, "wasm")
|
||||
else if (tc.isWindows())
|
||||
self.findVariantIndex(os_info.@"enum".variants, "windows")
|
||||
else if (tc.isAndroid())
|
||||
self.findVariantIndex(os_info.@"enum".variants, "android")
|
||||
else if (tc.isLinux())
|
||||
self.findVariantIndex(os_info.@"enum".variants, "linux")
|
||||
else if (tc.isIOS())
|
||||
|
||||
Reference in New Issue
Block a user