Skip to content

Commit f3ddba2

Browse files
fix various zig 0.15.0-dev.1092 issues except the custom panic handler (#43)
This seems to cover most things not working in Zig 0.15.0-dev.1092 except the custom panic handler
1 parent a538924 commit f3ddba2

File tree

9 files changed

+329
-307
lines changed

9 files changed

+329
-307
lines changed

examples/minimal/src/android-bind.zig

Lines changed: 254 additions & 254 deletions
Large diffs are not rendered by default.

examples/minimal/src/minimal.zig

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ fn nativeActivityOnCreate(activity: *androidbind.ANativeActivity, savedState: []
3737
\\ App pid: {}
3838
\\ Build mode: {s}
3939
\\ ABI: {s}-{s}-{s}
40-
\\ Compiler version: {}
40+
\\ Compiler version: {}.{}.{}
4141
\\ Compiler backend: {s}
4242
, .{
4343
"Minimal App", // build_options.app_name,
@@ -48,7 +48,9 @@ fn nativeActivityOnCreate(activity: *androidbind.ANativeActivity, savedState: []
4848
@tagName(builtin.cpu.arch),
4949
@tagName(builtin.os.tag),
5050
@tagName(builtin.abi),
51-
builtin.zig_version,
51+
builtin.zig_version.major,
52+
builtin.zig_version.minor,
53+
builtin.zig_version.patch,
5254
@tagName(builtin.zig_backend),
5355
});
5456

@@ -81,7 +83,7 @@ comptime {
8183
}
8284

8385
/// Android entry point
84-
fn NativeActivity_onCreate(activity: *androidbind.ANativeActivity, rawSavedState: ?[*]u8, rawSavedStateSize: usize) callconv(.C) void {
86+
fn NativeActivity_onCreate(activity: *androidbind.ANativeActivity, rawSavedState: ?[*]u8, rawSavedStateSize: usize) callconv(.c) void {
8587
const savedState: []const u8 = if (rawSavedState) |s|
8688
s[0..rawSavedStateSize]
8789
else
@@ -147,7 +149,7 @@ fn makeNativeActivityGlue(comptime App: type) androidbind.ANativeActivityCallbac
147149
}
148150

149151
// return value must be created with malloc(), so we pass the c_allocator to App.onSaveInstanceState
150-
fn onSaveInstanceState(activity: *androidbind.ANativeActivity, outSize: *usize) callconv(.C) ?[*]u8 {
152+
fn onSaveInstanceState(activity: *androidbind.ANativeActivity, outSize: *usize) callconv(.c) ?[*]u8 {
151153
outSize.* = 0;
152154
if (!@hasDecl(App, "onSaveInstanceState")) {
153155
log.debug("ANativeActivity callback onSaveInstanceState not available on {s}", .{@typeName(App)});
@@ -162,52 +164,52 @@ fn makeNativeActivityGlue(comptime App: type) androidbind.ANativeActivityCallbac
162164
return null;
163165
}
164166

165-
fn onDestroy(activity: *androidbind.ANativeActivity) callconv(.C) void {
167+
fn onDestroy(activity: *androidbind.ANativeActivity) callconv(.c) void {
166168
const instance = activity.instance orelse return;
167169
const app: *App = @ptrCast(@alignCast(instance));
168170
app.deinit();
169171
std.heap.c_allocator.destroy(app);
170172
}
171-
fn onStart(activity: *androidbind.ANativeActivity) callconv(.C) void {
173+
fn onStart(activity: *androidbind.ANativeActivity) callconv(.c) void {
172174
invoke(activity, "onStart", .{});
173175
}
174-
fn onResume(activity: *androidbind.ANativeActivity) callconv(.C) void {
176+
fn onResume(activity: *androidbind.ANativeActivity) callconv(.c) void {
175177
invoke(activity, "onResume", .{});
176178
}
177-
fn onPause(activity: *androidbind.ANativeActivity) callconv(.C) void {
179+
fn onPause(activity: *androidbind.ANativeActivity) callconv(.c) void {
178180
invoke(activity, "onPause", .{});
179181
}
180-
fn onStop(activity: *androidbind.ANativeActivity) callconv(.C) void {
182+
fn onStop(activity: *androidbind.ANativeActivity) callconv(.c) void {
181183
invoke(activity, "onStop", .{});
182184
}
183-
fn onConfigurationChanged(activity: *androidbind.ANativeActivity) callconv(.C) void {
185+
fn onConfigurationChanged(activity: *androidbind.ANativeActivity) callconv(.c) void {
184186
invoke(activity, "onConfigurationChanged", .{});
185187
}
186-
fn onLowMemory(activity: *androidbind.ANativeActivity) callconv(.C) void {
188+
fn onLowMemory(activity: *androidbind.ANativeActivity) callconv(.c) void {
187189
invoke(activity, "onLowMemory", .{});
188190
}
189-
fn onWindowFocusChanged(activity: *androidbind.ANativeActivity, hasFocus: c_int) callconv(.C) void {
191+
fn onWindowFocusChanged(activity: *androidbind.ANativeActivity, hasFocus: c_int) callconv(.c) void {
190192
invoke(activity, "onWindowFocusChanged", .{(hasFocus != 0)});
191193
}
192-
fn onNativeWindowCreated(activity: *androidbind.ANativeActivity, window: *androidbind.ANativeWindow) callconv(.C) void {
194+
fn onNativeWindowCreated(activity: *androidbind.ANativeActivity, window: *androidbind.ANativeWindow) callconv(.c) void {
193195
invoke(activity, "onNativeWindowCreated", .{window});
194196
}
195-
fn onNativeWindowResized(activity: *androidbind.ANativeActivity, window: *androidbind.ANativeWindow) callconv(.C) void {
197+
fn onNativeWindowResized(activity: *androidbind.ANativeActivity, window: *androidbind.ANativeWindow) callconv(.c) void {
196198
invoke(activity, "onNativeWindowResized", .{window});
197199
}
198-
fn onNativeWindowRedrawNeeded(activity: *androidbind.ANativeActivity, window: *androidbind.ANativeWindow) callconv(.C) void {
200+
fn onNativeWindowRedrawNeeded(activity: *androidbind.ANativeActivity, window: *androidbind.ANativeWindow) callconv(.c) void {
199201
invoke(activity, "onNativeWindowRedrawNeeded", .{window});
200202
}
201-
fn onNativeWindowDestroyed(activity: *androidbind.ANativeActivity, window: *androidbind.ANativeWindow) callconv(.C) void {
203+
fn onNativeWindowDestroyed(activity: *androidbind.ANativeActivity, window: *androidbind.ANativeWindow) callconv(.c) void {
202204
invoke(activity, "onNativeWindowDestroyed", .{window});
203205
}
204-
fn onInputQueueCreated(activity: *androidbind.ANativeActivity, input_queue: *androidbind.AInputQueue) callconv(.C) void {
206+
fn onInputQueueCreated(activity: *androidbind.ANativeActivity, input_queue: *androidbind.AInputQueue) callconv(.c) void {
205207
invoke(activity, "onInputQueueCreated", .{input_queue});
206208
}
207-
fn onInputQueueDestroyed(activity: *androidbind.ANativeActivity, input_queue: *androidbind.AInputQueue) callconv(.C) void {
209+
fn onInputQueueDestroyed(activity: *androidbind.ANativeActivity, input_queue: *androidbind.AInputQueue) callconv(.c) void {
208210
invoke(activity, "onInputQueueDestroyed", .{input_queue});
209211
}
210-
fn onContentRectChanged(activity: *androidbind.ANativeActivity, rect: *const androidbind.ARect) callconv(.C) void {
212+
fn onContentRectChanged(activity: *androidbind.ANativeActivity, rect: *const androidbind.ARect) callconv(.c) void {
211213
invoke(activity, "onContentRectChanged", .{rect});
212214
}
213215
};

examples/sdl2/src/sdl-zig-demo.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ comptime {
2727
}
2828

2929
/// This needs to be exported for Android builds
30-
fn SDL_main() callconv(.C) void {
30+
fn SDL_main() callconv(.c) void {
3131
if (comptime builtin.abi.isAndroid()) {
3232
_ = std.start.callMain();
3333
} else {

examples/sdl2/third-party/sdl2/build.zig

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,14 @@ pub fn build(b: *std.Build) !void {
1010
const sdl_include_path = sdl_path.path(b, "include");
1111

1212
const is_shared_library = target.result.abi.isAndroid(); // NOTE(jae): 2024-09-22: Android uses shared library as SDL2 loads it as part of SDLActivity.java
13-
const lib = if (!is_shared_library) b.addStaticLibrary(.{
13+
const lib = b.addLibrary(.{
1414
.name = "SDL2",
15-
.target = target,
16-
.optimize = optimize,
17-
.link_libc = true,
18-
}) else b.addSharedLibrary(.{
19-
.name = "SDL2",
20-
.target = target,
21-
.optimize = optimize,
22-
.link_libc = true,
15+
.root_module = b.createModule(.{
16+
.target = target,
17+
.optimize = optimize,
18+
.link_libc = true,
19+
}),
20+
.linkage = if (is_shared_library) .dynamic else .static,
2321
});
2422

2523
lib.addCSourceFiles(.{

src/android/android.zig

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,10 @@ const LogWriter = struct {
103103
line_len: usize = 0,
104104

105105
const Error = error{};
106-
const Writer = std.io.Writer(*@This(), Error, write);
106+
const Writer = if (builtin.zig_version.major == 0 and builtin.zig_version.minor == 14)
107+
std.io.Writer(*@This(), Error, write)
108+
else
109+
std.io.GenericWriter(*@This(), Error, write);
107110

108111
fn write(self: *@This(), buffer: []const u8) Error!usize {
109112
for (buffer) |char| {
@@ -168,8 +171,11 @@ const Panic = struct {
168171
/// This is used to catch and handle panics triggered by the panic handler.
169172
threadlocal var panic_stage: usize = 0;
170173

174+
const is_zig_014_or_less = (builtin.zig_version.major == 0 and builtin.zig_version.minor <= 14);
175+
171176
fn panic(message: []const u8, ret_addr: ?usize) noreturn {
172177
@branchHint(.cold);
178+
if (!is_zig_014_or_less) @compileError("Android Panic needs to be updated to the newer io.Writer vtable implementation to work in Zig 0.15.0+");
173179
if (comptime !builtin.abi.isAndroid()) @compileError("do not use Android panic for non-Android builds");
174180
const first_trace_addr = ret_addr orelse @returnAddress();
175181
panicImpl(first_trace_addr, message);
@@ -223,12 +229,6 @@ const Panic = struct {
223229
}
224230

225231
const io = struct {
226-
const tty = struct {
227-
inline fn detectConfig(_: *LogWriter) std.io.tty.Config {
228-
return .no_color;
229-
}
230-
};
231-
232232
var writer = LogWriter{
233233
.level = .fatal,
234234
};
@@ -307,14 +307,13 @@ const Panic = struct {
307307

308308
fn dumpStackTrace(stack_trace: std.builtin.StackTrace) void {
309309
nosuspend {
310+
const stderr = io.getStdErr().writer();
310311
if (comptime builtin.target.cpu.arch.isWasm()) {
311312
if (native_os == .wasi) {
312-
const stderr = io.getStdErr().writer();
313313
stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return;
314314
}
315315
return;
316316
}
317-
const stderr = io.getStdErr().writer();
318317
if (builtin.strip_debug_info) {
319318
stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
320319
return;
@@ -325,13 +324,13 @@ const Panic = struct {
325324
};
326325
if (builtin.zig_version.major == 0 and builtin.zig_version.minor == 13) {
327326
// Legacy 0.13.0
328-
writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, io.tty.detectConfig(io.getStdErr())) catch |err| {
327+
writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, .no_color) catch |err| {
329328
stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return;
330329
return;
331330
};
332331
} else {
333332
// 0.14.0-dev+
334-
writeStackTrace(stack_trace, stderr, debug_info, io.tty.detectConfig(io.getStdErr())) catch |err| {
333+
writeStackTrace(stack_trace, stderr, debug_info, .no_color) catch |err| {
335334
stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return;
336335
return;
337336
};
@@ -342,14 +341,13 @@ const Panic = struct {
342341
const writeCurrentStackTrace = std.debug.writeCurrentStackTrace;
343342
fn dumpCurrentStackTrace(start_addr: ?usize) void {
344343
nosuspend {
344+
const stderr = io.getStdErr().writer();
345345
if (comptime builtin.target.cpu.arch.isWasm()) {
346346
if (native_os == .wasi) {
347-
const stderr = io.getStdErr().writer();
348347
stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return;
349348
}
350349
return;
351350
}
352-
const stderr = io.getStdErr().writer();
353351
if (builtin.strip_debug_info) {
354352
stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
355353
return;
@@ -358,7 +356,7 @@ const Panic = struct {
358356
stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;
359357
return;
360358
};
361-
writeCurrentStackTrace(stderr, debug_info, io.tty.detectConfig(io.getStdErr()), start_addr) catch |err| {
359+
writeCurrentStackTrace(stderr, debug_info, .no_color, start_addr) catch |err| {
362360
stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return;
363361
return;
364362
};

src/androidbuild/androidbuild.zig

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,22 +100,25 @@ pub fn runNameContext(comptime name: []const u8) []const u8 {
100100
pub fn printErrorsAndExit(message: []const u8, errors: []const []const u8) noreturn {
101101
nosuspend {
102102
log.err("{s}", .{message});
103-
const stderr = std.io.getStdErr().writer();
103+
const stderr = if (builtin.zig_version.major == 0 and builtin.zig_version.minor <= 14)
104+
std.io.getStdErr().writer()
105+
else
106+
std.fs.File.stderr();
104107
std.debug.lockStdErr();
105108
defer std.debug.unlockStdErr();
106109
for (errors) |err| {
107110
var it = std.mem.splitScalar(u8, err, '\n');
108111
const headline = it.next() orelse continue;
109112
stderr.writeAll("- ") catch {};
110113
stderr.writeAll(headline) catch {};
111-
stderr.writeByte('\n') catch {};
114+
stderr.writeAll("\n") catch {};
112115
while (it.next()) |line| {
113116
stderr.writeAll(" ") catch {};
114117
stderr.writeAll(line) catch {};
115-
stderr.writeByte('\n') catch {};
118+
stderr.writeAll("\n") catch {};
116119
}
117120
}
118-
stderr.writeByte('\n') catch {};
121+
stderr.writeAll("\n") catch {};
119122
}
120123
std.process.exit(1);
121124
}

src/androidbuild/apk.zig

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ fn applyLibLinkCppWorkaroundIssue19(apk: *Apk, artifact: *Step.Compile) void {
786786
const b = apk.b;
787787

788788
const should_apply_fix = (artifact.root_module.link_libcpp == true or
789-
artifact.dependsOnSystemLibrary("c++abi_zig_workaround"));
789+
dependsOnSystemLibrary(artifact, "c++abi_zig_workaround"));
790790
if (!should_apply_fix) {
791791
return;
792792
}
@@ -821,6 +821,22 @@ fn applyLibLinkCppWorkaroundIssue19(apk: *Apk, artifact: *Step.Compile) void {
821821
}
822822
}
823823

824+
/// Copy-paste of "dependsOnSystemLibrary" that only checks if that system library is included to
825+
/// workaround a bug with in Zig 0.15.0-dev.1092+d772c0627
826+
fn dependsOnSystemLibrary(compile: *Step.Compile, name: []const u8) bool {
827+
for (compile.getCompileDependencies(true)) |some_compile| {
828+
for (some_compile.root_module.getGraph().modules) |mod| {
829+
for (mod.link_objects.items) |lo| {
830+
switch (lo) {
831+
.system_lib => |lib| if (std.mem.eql(u8, lib.name, name)) return true,
832+
else => {},
833+
}
834+
}
835+
}
836+
}
837+
return false;
838+
}
839+
824840
fn updateSharedLibraryOptions(artifact: *std.Build.Step.Compile) void {
825841
if (artifact.linkage) |linkage| {
826842
if (linkage != .dynamic) {

src/androidbuild/builtin_options_update.zig

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@ fn make(step: *Step, _: Build.Step.MakeOptions) !void {
4141
const builtin_options_update: *BuiltinOptionsUpdate = @fieldParentPtr("step", step);
4242
const options = builtin_options_update.options;
4343

44-
const package_name_path = builtin_options_update.package_name_stdout.getPath2(b, step);
44+
const package_name_path = builtin_options_update.package_name_stdout.getPath3(b, step);
4545

46-
const file = try fs.openFileAbsolute(package_name_path, .{});
46+
// NOTE(jae): 2025-07-23
47+
// As of Zig 0.15.0-dev.1092+d772c0627, package_name_path.openFile("") is not possible as it assumes you're appending *something*
48+
const file = try package_name_path.root_dir.handle.openFile(package_name_path.sub_path, .{});
4749

4850
// Read package name from stdout and strip line feed / carriage return
4951
// ie. "com.zig.sdl2\n\r"

src/androidbuild/d8glob.zig

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ fn make(step: *Step, _: Build.Step.MakeOptions) !void {
4848
const glob: *@This() = @fieldParentPtr("step", step);
4949
const d8 = glob.run;
5050

51-
const search_dir = glob.dir.getPath2(b, step);
51+
const search_dir = glob.dir.getPath3(b, step);
5252

5353
// NOTE(jae): 2024-09-22
5454
// Change current working directory to where the Java classes are
@@ -62,8 +62,11 @@ fn make(step: *Step, _: Build.Step.MakeOptions) !void {
6262
// - If "d8" has the ability to pass a file of command line parameters, that would work too but I haven't seen any in the docs
6363
d8.setCwd(glob.dir);
6464

65-
var dir = try fs.openDirAbsolute(search_dir, .{ .iterate = true });
65+
// NOTE(jae): 2025-07-23
66+
// As of Zig 0.15.0-dev.1092+d772c0627, package_name_path.openDir("") is not possible as it assumes you're appending a sub-path
67+
var dir = try search_dir.root_dir.handle.openDir(search_dir.sub_path, .{ .iterate = true });
6668
defer dir.close();
69+
6770
var walker = try dir.walk(arena);
6871
defer walker.deinit();
6972
while (try walker.next()) |entry| {
@@ -83,7 +86,7 @@ fn make(step: *Step, _: Build.Step.MakeOptions) !void {
8386
// This is to avoid the Java error "command line too long" that can occur with d8
8487
d8.addArg(entry.path);
8588
d8.addFileInput(LazyPath{
86-
.cwd_relative = try fs.path.resolve(arena, &.{ search_dir, entry.path }),
89+
.cwd_relative = try search_dir.root_dir.join(b.allocator, &.{ search_dir.sub_path, entry.path }),
8790
});
8891
}
8992
}

0 commit comments

Comments
 (0)