From 4608be07edf01eca56b9d37b8a4e42799d79f244 Mon Sep 17 00:00:00 2001 From: Jae B Date: Wed, 4 Feb 2026 12:57:00 +1100 Subject: [PATCH] improve asset directory to support generated directories --- examples/sdl2/build.zig | 4 ++ examples/sdl2/src/sdl-zig-demo.zig | 11 ++-- examples/sdl2/third-party/sdl2/build.zig | 2 +- src/androidbuild/DirectoryFileInput.zig | 76 ++++++++++++++++++++++++ src/androidbuild/apk.zig | 26 ++------ 5 files changed, 91 insertions(+), 28 deletions(-) create mode 100644 src/androidbuild/DirectoryFileInput.zig diff --git a/examples/sdl2/build.zig b/examples/sdl2/build.zig index ba3ce55..3242b53 100644 --- a/examples/sdl2/build.zig +++ b/examples/sdl2/build.zig @@ -37,6 +37,10 @@ pub fn build(b: *std.Build) void { const key_store_file = android_sdk.createKeyStore(.example); apk.setKeyStore(key_store_file); apk.setAndroidManifest(b.path("android/AndroidManifest.xml")); + + const generated_asset_dir = b.addNamedWriteFiles("android_asset_directory"); + _ = generated_asset_dir.addCopyFile(b.path("src/zig.bmp"), "zig.bmp"); + apk.addAssetDirectory(generated_asset_dir.getDirectory()); apk.addResourceDirectory(b.path("android/res")); // Add Java files diff --git a/examples/sdl2/src/sdl-zig-demo.zig b/examples/sdl2/src/sdl-zig-demo.zig index 819c358..6055f1c 100644 --- a/examples/sdl2/src/sdl-zig-demo.zig +++ b/examples/sdl2/src/sdl-zig-demo.zig @@ -69,11 +69,12 @@ pub fn main() !void { }; defer sdl.SDL_DestroyRenderer(renderer); - const zig_bmp = @embedFile("zig.bmp"); - const rw = sdl.SDL_RWFromConstMem(zig_bmp, zig_bmp.len) orelse { - log.info("Unable to get RWFromConstMem: {s}", .{sdl.SDL_GetError()}); - return error.SDLInitializationFailed; - }; + const rw = sdl.SDL_RWFromFile(if (builtin.abi.isAndroid()) + // For Android, we setup the build to dynamically add "zig.bmp" to the Android assets folder + // so it's accessible without "src/" prefix + "zig.bmp" + else + "src/zig.bmp", "rb"); defer assert(sdl.SDL_RWclose(rw) == 0); const zig_surface = sdl.SDL_LoadBMP_RW(rw, 0) orelse { diff --git a/examples/sdl2/third-party/sdl2/build.zig b/examples/sdl2/third-party/sdl2/build.zig index 7641cca..272dfee 100644 --- a/examples/sdl2/third-party/sdl2/build.zig +++ b/examples/sdl2/third-party/sdl2/build.zig @@ -266,7 +266,7 @@ const generic_src_files = [_][]const u8{ "src/stdlib/SDL_malloc.c", "src/stdlib/SDL_mslibc.c", "src/stdlib/SDL_qsort.c", - //"src/stdlib/SDL_stdmod.c", // Removed between 2.32.2 and 2.32.10 + "src/stdlib/SDL_stdlib.c", // "src/stdlib/SDL_stdmod.c", // Renamed between 2.32.2 and 2.32.10 "src/stdlib/SDL_string.c", "src/stdlib/SDL_strtokr.c", "src/thread/SDL_thread.c", diff --git a/src/androidbuild/DirectoryFileInput.zig b/src/androidbuild/DirectoryFileInput.zig new file mode 100644 index 0000000..d9ee847 --- /dev/null +++ b/src/androidbuild/DirectoryFileInput.zig @@ -0,0 +1,76 @@ +//! DirectoryFileInput adds files within a directory to the dependencies of the given Step.Run command +//! This is required so that generated directories will work. + +const std = @import("std"); +const androidbuild = @import("androidbuild.zig"); +const builtin = @import("builtin"); +const Build = std.Build; +const Step = Build.Step; +const Run = Build.Step.Run; +const LazyPath = Build.LazyPath; +const fs = std.fs; +const mem = std.mem; +const assert = std.debug.assert; + +step: Step, + +/// Runner to update +run: *Build.Step.Run, + +/// The directory that will contain the files to glob +dir: LazyPath, + +pub fn create(owner: *std.Build, run: *Run, dir: LazyPath) void { + const self = owner.allocator.create(DirectoryFileInput) catch @panic("OOM"); + self.* = .{ + .step = Step.init(.{ + .id = .custom, + .name = androidbuild.runNameContext("directory-file-input"), + .owner = owner, + .makeFn = make, + }), + .run = run, + .dir = dir, + }; + // Run step relies on DirectoryFileInput finishing + run.step.dependOn(&self.step); + // If dir is generated then this will wait for that dir to generate + dir.addStepDependencies(&self.step); +} + +fn make(step: *Step, _: Build.Step.MakeOptions) !void { + const b = step.owner; + const arena = b.allocator; + const self: *DirectoryFileInput = @fieldParentPtr("step", step); + + const run = self.run; + const dir_path = self.dir.getPath3(b, step); + + // NOTE(jae): 2025-07-23 + // 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 + var dir = if (builtin.zig_version.major == 0 and builtin.zig_version.minor <= 15) + try dir_path.root_dir.handle.openDir(dir_path.sub_path, .{ .iterate = true }) + else + try dir_path.root_dir.handle.openDir(b.graph.io, dir_path.sub_path, .{ .iterate = true }); + defer if (builtin.zig_version.major == 0 and builtin.zig_version.minor <= 15) + dir.close() + else + dir.close(b.graph.io); + + var walker = try dir.walk(arena); + defer walker.deinit(); + while (if (builtin.zig_version.major == 0 and builtin.zig_version.minor <= 15) + try walker.next() + else + try walker.next(b.graph.io)) |entry| + { + if (entry.kind != .file) continue; + + // Add file as dependency to run command + run.addFileInput(LazyPath{ + .cwd_relative = try dir_path.root_dir.join(b.allocator, &.{ dir_path.sub_path, entry.path }), + }); + } +} + +const DirectoryFileInput = @This(); diff --git a/src/androidbuild/apk.zig b/src/androidbuild/apk.zig index cd93419..b53c03a 100644 --- a/src/androidbuild/apk.zig +++ b/src/androidbuild/apk.zig @@ -3,6 +3,7 @@ const builtin = @import("builtin"); const androidbuild = @import("androidbuild.zig"); const Sdk = @import("tools.zig"); const BuiltinOptionsUpdate = @import("builtin_options_update.zig"); +const DirectoryFileInput = @import("DirectoryFileInput.zig"); const Ndk = @import("Ndk.zig"); const BuildTools = @import("BuildTools.zig"); @@ -362,28 +363,8 @@ fn doInstallApk(apk: *Apk) std.mem.Allocator.Error!*Step.InstallFile { .directory => |asset_dir_path| { aapt2link.addArg("-A"); aapt2link.addDirectoryArg(asset_dir_path.source); - - var asset_dir = ( - if (builtin.zig_version.major == 0 and builtin.zig_version.minor <= 15) - asset_dir_path.source.getPath3(b, null).openDir("", .{ .iterate = true }) - else - (asset_dir_path.source.getPath4(b, null) catch |err| @panic(@errorName(err))).openDir(b.graph.io, "", .{ .iterate = true }) - ) catch |err| @panic(@errorName(err)); - - defer if (builtin.zig_version.major == 0 and builtin.zig_version.minor <= 15) asset_dir.close() else asset_dir.close(b.graph.io); - - var walker = try asset_dir.walk(b.allocator); - defer walker.deinit(); - - while (( - if (builtin.zig_version.major == 0 and builtin.zig_version.minor <= 15) - walker.next() - else - walker.next(b.graph.io) - ) catch |err| @panic(@errorName(err))) |entry| { - if (entry.kind == .file) aapt2link.addFileInput(try asset_dir_path.source.join(b.allocator, entry.path)); - } - } + DirectoryFileInput.create(b, aapt2link, asset_dir_path.source); + }, } } @@ -404,6 +385,7 @@ fn doInstallApk(apk: *Apk) std.mem.Allocator.Error!*Step.InstallFile { // add directory aapt2compile.addArg("--dir"); aapt2compile.addDirectoryArg(resource_directory.source); + DirectoryFileInput.create(b, aapt2compile, resource_directory.source); aapt2compile.addArg("-o"); const resources_flat_zip_file = aapt2compile.addOutputFileArg("resource_dir.flat.zip");