diff --git a/build.zig b/build.zig index 6da6662..2ba8b76 100644 --- a/build.zig +++ b/build.zig @@ -76,6 +76,8 @@ pub fn build(b: *std.Build) void { .target = target, .optimize = optimize, }); + zig016.addImport("ndk", ndk_module); + zig016.addImport("android_builtin", android_builtin_module); android_module.addImport("zig016", zig016); } diff --git a/examples/minimal/src/minimal.zig b/examples/minimal/src/minimal.zig index 96548ac..43d4b1a 100644 --- a/examples/minimal/src/minimal.zig +++ b/examples/minimal/src/minimal.zig @@ -12,8 +12,8 @@ pub const std_options: std.Options = if (builtin.abi.isAndroid()) else .{}; -/// Deprecated: Zig 0.15.2 and lower only, Custom panic handler for Android -pub const panic = if (builtin.abi.isAndroid() and builtin.zig_version.major == 0 and builtin.zig_version.minor <= 15) +/// Custom panic handler for Android +pub const panic = if (builtin.abi.isAndroid()) android.panic else std.debug.FullPanic(std.debug.defaultPanic); diff --git a/examples/raylib/src/main.zig b/examples/raylib/src/main.zig index 3d57302..6617613 100644 --- a/examples/raylib/src/main.zig +++ b/examples/raylib/src/main.zig @@ -19,8 +19,8 @@ pub fn main() !void { } } -/// Deprecated: Zig 0.15.2 and lower only, Custom panic handler for Android -pub const panic = if (builtin.abi.isAndroid() and builtin.zig_version.major == 0 and builtin.zig_version.minor <= 15) +/// Custom panic handler for Android +pub const panic = if (builtin.abi.isAndroid()) android.panic else std.debug.FullPanic(std.debug.defaultPanic); diff --git a/examples/sdl2/src/sdl-zig-demo.zig b/examples/sdl2/src/sdl-zig-demo.zig index 6055f1c..182ba93 100644 --- a/examples/sdl2/src/sdl-zig-demo.zig +++ b/examples/sdl2/src/sdl-zig-demo.zig @@ -14,8 +14,8 @@ pub const std_options: std.Options = if (builtin.abi.isAndroid()) else .{}; -/// Deprecated: Zig 0.15.2 and lower only, Custom panic handler for Android -pub const panic = if (builtin.abi.isAndroid() and builtin.zig_version.major == 0 and builtin.zig_version.minor <= 15) +// Custom panic handler for Android +pub const panic = if (builtin.abi.isAndroid()) android.panic else std.debug.FullPanic(std.debug.defaultPanic); @@ -28,24 +28,23 @@ comptime { /// This needs to be exported for Android builds fn SDL_main() callconv(.c) void { - if (comptime builtin.abi.isAndroid()) { - if (builtin.zig_version.major == 0 and builtin.zig_version.minor <= 14) { - _ = std.start.callMain(); - } else if (builtin.zig_version.major == 0 and builtin.zig_version.minor <= 15) { - main() catch |err| { - log.err("{s}", .{@errorName(err)}); - if (@errorReturnTrace()) |trace| { - if (builtin.zig_version.major == 0 and builtin.zig_version.minor <= 15) { - std.debug.dumpStackTrace(trace.*); - } else { - std.debug.dumpStackTrace(trace); - } - } - }; - } - } else { + if (!comptime builtin.abi.isAndroid()) { @compileError("SDL_main should not be called outside of Android builds"); } + if (builtin.zig_version.major == 0 and builtin.zig_version.minor <= 14) { + _ = std.start.callMain(); + return; + } + main() catch |err| { + log.err("{s}", .{@errorName(err)}); + if (@errorReturnTrace()) |trace| { + if (builtin.zig_version.major == 0 and builtin.zig_version.minor <= 15) { + std.debug.dumpStackTrace(trace.*); + } else { + std.debug.dumpStackTrace(trace); + } + } + }; } pub fn main() !void { diff --git a/src/android/android.zig b/src/android/android.zig index 89445f8..9b530c7 100644 --- a/src/android/android.zig +++ b/src/android/android.zig @@ -13,7 +13,7 @@ const Level = ndk.Level; pub const panic = if (builtin.zig_version.major == 0 and builtin.zig_version.minor <= 15) std.debug.FullPanic(@import("Zig015_Panic.zig").panic) else - @compileError("Android panic handler is no longer maintained as of Zig 0.16.x-dev"); + std.debug.FullPanic(zig016.panic); /// Alternate log function implementation that calls __android_log_write so that you can see the logging via "adb logcat" pub const logFn = if (builtin.zig_version.major == 0 and builtin.zig_version.minor <= 14) diff --git a/src/android/zig016/zig016.zig b/src/android/zig016/zig016.zig index 413a6e4..2d831ec 100644 --- a/src/android/zig016/zig016.zig +++ b/src/android/zig016/zig016.zig @@ -1,6 +1,11 @@ //! Seperate module for Zig 0.16.X-dev functionality as @Type() comptime directive was removed const std = @import("std"); +const builtin = @import("builtin"); +const ndk = @import("ndk"); + +const android_builtin = @import("android_builtin"); +const package_name: ?[*:0]const u8 = if (android_builtin.package_name.len > 0) android_builtin.package_name else null; const LogFunction = fn (comptime message_level: std.log.Level, comptime scope: @EnumLiteral(), comptime format: []const u8, args: anytype) void; @@ -20,3 +25,78 @@ pub fn wrapLogFn(comptime logFn: fn ( } }.standardLogFn; } + +pub fn panic(message: []const u8, first_trace_addr: ?usize) noreturn { + @branchHint(.cold); + if (comptime !builtin.abi.isAndroid()) @compileError("do not use Android panic for non-Android builds"); + + const android_log_level: c_int = @intFromEnum(ndk.Level.fatal); + + trace: { + _ = ndk.__android_log_print(android_log_level, package_name, "panic: %.*s", message.len, message.ptr); + + if (@errorReturnTrace()) |t| if (t.index > 0) { + logFatal("error return context:"); + writeStackTrace(t) catch break :trace; + logFatal("\nstack trace:\n"); + }; + if (!std.options.allow_stack_tracing) { + logFatal("Cannot print stack trace: stack tracing is disabled"); + return; + } else { + _ = ndk.__android_log_print(android_log_level, package_name, " at address: 0x%X", first_trace_addr orelse @returnAddress()); + logFatal(" (stack trace printing not supported in Zig 0.16.X+ for Android SDK)"); + } + } + + @trap(); +} + +/// Write a previously captured stack trace to `writer`, annotated with source locations. +pub fn writeStackTrace(st: *const std.builtin.StackTrace) !void { + if (!std.options.allow_stack_tracing) { + logFatal("Cannot print stack trace: stack tracing is disabled"); + return; + } + + // Fetch `st.index` straight away. Aside from avoiding redundant loads, this prevents issues if + // `st` is `@errorReturnTrace()` and errors are encountered while writing the stack trace. + const n_frames = st.index; + if (n_frames == 0) return logFatal("(empty stack trace)"); + + const captured_frames = @min(n_frames, st.instruction_addresses.len); + logFatal("(stack trace support unimplemented for Zig 0.16.X+)"); + + // const di_gpa = std.debug.getDebugInfoAllocator(); + // const di = std.debug.getSelfDebugInfo() catch |err| switch (err) { + // error.UnsupportedTarget => { + // logFatal("Cannot print stack trace: debug info unavailable for target\n\n"); + // return; + // }, + // }; + // const io = std.Options.debug_io; + // + // for (st.instruction_addresses[0..captured_frames]) |ret_addr| { + // // `ret_addr` is the return address, which is *after* the function call. + // // Subtract 1 to get an address *in* the function call for a better source location. + // try printSourceAtAddress(di_gpa, io, di, t, ret_addr -| StackIterator.ra_call_offset); + // } + if (n_frames > captured_frames) { + _ = ndk.__android_log_print( + @intFromEnum(ndk.Level.fatal), + package_name, + "(%d additional stack frames skipped...)", + n_frames - captured_frames, + ); + } +} + +inline fn logFatal(text: []const u8) void { + _ = ndk.__android_log_print( + @intFromEnum(ndk.Level.fatal), + package_name, + "%.*s", + text.len, + text.ptr, + ); +}