ffi #jni_main R.2: drop native_app_glue from Android link when #jni_main present
`target.link` now takes a `has_jni_main: bool` parameter (passed by
main.zig from `comp.getJniMainEmissions().len > 0`). When set:
- native_app_glue.c is not compiled — no `.glue.o` produced.
- `-u ANativeActivity_onCreate` is not added to the link argv.
- The Java-driven Activity is the entry; the .so just provides JNI
impls, bound at load time via the `JNI_OnLoad` slice R.3 will
synthesize.
Legacy NativeActivity builds (no `#jni_main` decl) are unchanged: glue
is still compiled and `ANativeActivity_onCreate` still retained.
Verified end-to-end:
- #jni_main .so: `llvm-nm -D` shows neither `ANativeActivity_onCreate`
nor `android_main` (correct — Java side drives entry).
- Legacy .so (99-android-egl-clear): both symbols still exported.
131 host / 4 cross / zig build test all green.
This commit is contained in:
@@ -595,7 +595,7 @@ fn compileWithTimer(allocator: std.mem.Allocator, io: std.Io, input_path: []cons
|
||||
|
||||
// Link (sx .o + C .o files)
|
||||
timer.mark();
|
||||
sx.target.link(allocator, io, obj_path, c_obj_paths, final_output, libs, fws, merged_config) catch {
|
||||
sx.target.link(allocator, io, obj_path, c_obj_paths, final_output, libs, fws, merged_config, comp.getJniMainEmissions().len > 0) catch {
|
||||
std.debug.print("error: linking failed\n", .{});
|
||||
return error.CompileError;
|
||||
};
|
||||
|
||||
@@ -686,7 +686,7 @@ pub fn discoverAppleSdk(allocator: std.mem.Allocator, io: std.Io, sdk_name: []co
|
||||
return out;
|
||||
}
|
||||
|
||||
pub fn link(allocator: std.mem.Allocator, io: std.Io, output_obj: []const u8, extra_objects: []const []const u8, output_bin: []const u8, libraries: []const []const u8, frameworks: []const []const u8, target_config: TargetConfig) !void {
|
||||
pub fn link(allocator: std.mem.Allocator, io: std.Io, output_obj: []const u8, extra_objects: []const []const u8, output_bin: []const u8, libraries: []const []const u8, frameworks: []const []const u8, target_config: TargetConfig, has_jni_main: bool) !void {
|
||||
var argv = std.ArrayList([]const u8).empty;
|
||||
|
||||
if (target_config.isIOS()) {
|
||||
@@ -733,13 +733,24 @@ pub fn link(allocator: std.mem.Allocator, io: std.Io, output_obj: []const u8, ex
|
||||
while (it.next()) |part| try argv.append(allocator, part);
|
||||
}
|
||||
} else if (target_config.isAndroid()) {
|
||||
// Android: NDK clang. Produces a shared library (.so) loaded by
|
||||
// NativeActivity. native_app_glue.c (from the NDK) is compiled and
|
||||
// linked alongside the sx code so apps can use the conventional
|
||||
// `android_main(struct android_app*)` event-loop shape — the glue
|
||||
// owns `ANativeActivity_onCreate` and forwards into android_main on
|
||||
// a dedicated thread. `-u ANativeActivity_onCreate` keeps the glue's
|
||||
// symbol from being stripped (nothing in our .o references it).
|
||||
// Android: NDK clang. Produces a shared library (.so).
|
||||
//
|
||||
// Two entry shapes:
|
||||
//
|
||||
// - **#jni_main path (`has_jni_main = true`)** — the Java side
|
||||
// drives lifecycle (the bundled classes.dex declares an
|
||||
// Activity that overrides `onCreate` etc.). The .so just
|
||||
// provides JNI implementations bound at load time via the
|
||||
// `JNI_OnLoad` synthesized in slice R.3. No native_app_glue
|
||||
// is needed: there's no `ANativeActivity_onCreate` to host,
|
||||
// no `android_main` event loop to run.
|
||||
//
|
||||
// - **Legacy NativeActivity path (`has_jni_main = false`)** —
|
||||
// native_app_glue.c is compiled and linked alongside the sx
|
||||
// code; the glue owns `ANativeActivity_onCreate` and forwards
|
||||
// into the user's `android_main` on a worker thread. The
|
||||
// `-u ANativeActivity_onCreate` keeps the glue's symbol from
|
||||
// being stripped (nothing in our .o references it).
|
||||
//
|
||||
// The `libraries` parameter (collected from `#library` directives)
|
||||
// and `frameworks` parameter (Apple-only by definition) are
|
||||
@@ -755,19 +766,22 @@ pub fn link(allocator: std.mem.Allocator, io: std.Io, output_obj: []const u8, ex
|
||||
const host_tag: []const u8 = if (@import("builtin").os.tag == .macos) "darwin-x86_64" else "linux-x86_64";
|
||||
const clang = try std.fmt.allocPrint(allocator, "{s}/toolchains/llvm/prebuilt/{s}/bin/clang", .{ ndk_root, host_tag });
|
||||
|
||||
const glue_src = try std.fmt.allocPrint(allocator, "{s}/sources/android/native_app_glue/android_native_app_glue.c", .{ndk_root});
|
||||
const glue_obj = try std.fmt.allocPrint(allocator, "{s}.glue.o", .{output_obj});
|
||||
var glue_argv = std.ArrayList([]const u8).empty;
|
||||
try glue_argv.appendSlice(allocator, &.{ clang, "-c", "-fPIC" });
|
||||
if (target_config.triple) |t| {
|
||||
try glue_argv.append(allocator, "-target");
|
||||
try glue_argv.append(allocator, std.mem.span(t));
|
||||
}
|
||||
try glue_argv.appendSlice(allocator, &.{ glue_src, "-o", glue_obj });
|
||||
const glue_slice = try glue_argv.toOwnedSlice(allocator);
|
||||
var glue_child = std.process.spawn(io, .{ .argv = glue_slice }) catch return error.LinkError;
|
||||
const glue_term = glue_child.wait(io) catch return error.LinkError;
|
||||
if (glue_term != .exited or glue_term.exited != 0) return error.LinkError;
|
||||
const glue_obj_opt: ?[]const u8 = if (has_jni_main) null else blk: {
|
||||
const glue_src = try std.fmt.allocPrint(allocator, "{s}/sources/android/native_app_glue/android_native_app_glue.c", .{ndk_root});
|
||||
const glue_obj = try std.fmt.allocPrint(allocator, "{s}.glue.o", .{output_obj});
|
||||
var glue_argv = std.ArrayList([]const u8).empty;
|
||||
try glue_argv.appendSlice(allocator, &.{ clang, "-c", "-fPIC" });
|
||||
if (target_config.triple) |t| {
|
||||
try glue_argv.append(allocator, "-target");
|
||||
try glue_argv.append(allocator, std.mem.span(t));
|
||||
}
|
||||
try glue_argv.appendSlice(allocator, &.{ glue_src, "-o", glue_obj });
|
||||
const glue_slice = try glue_argv.toOwnedSlice(allocator);
|
||||
var glue_child = std.process.spawn(io, .{ .argv = glue_slice }) catch return error.LinkError;
|
||||
const glue_term = glue_child.wait(io) catch return error.LinkError;
|
||||
if (glue_term != .exited or glue_term.exited != 0) return error.LinkError;
|
||||
break :blk glue_obj;
|
||||
};
|
||||
|
||||
try argv.append(allocator, clang);
|
||||
if (target_config.triple) |t| {
|
||||
@@ -776,9 +790,11 @@ pub fn link(allocator: std.mem.Allocator, io: std.Io, output_obj: []const u8, ex
|
||||
}
|
||||
try argv.append(allocator, "-shared");
|
||||
try argv.append(allocator, "-fPIC");
|
||||
try argv.appendSlice(allocator, &.{ "-u", "ANativeActivity_onCreate" });
|
||||
if (!has_jni_main) {
|
||||
try argv.appendSlice(allocator, &.{ "-u", "ANativeActivity_onCreate" });
|
||||
}
|
||||
try argv.append(allocator, output_obj);
|
||||
try argv.append(allocator, glue_obj);
|
||||
if (glue_obj_opt) |go| try argv.append(allocator, go);
|
||||
for (extra_objects) |eo| try argv.append(allocator, eo);
|
||||
try argv.append(allocator, "-o");
|
||||
try argv.append(allocator, output_bin);
|
||||
|
||||
Reference in New Issue
Block a user