Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,15 @@ jobs:
with:
version: ${{ needs.setup.outputs.zig-stable-version }}

- name: Build Test (Zig Stable)
run: zig build -Dandroid=true --verbose
working-directory: test/build
- name: Build Test
run: zig build --verbose
working-directory: test

- name: Build Minimal Example (Zig Stable)
- name: Build Minimal Example
run: zig build -Dandroid=true --verbose
working-directory: examples/minimal

- name: Build SDL2 Example (Zig Stable)
- name: Build SDL2 Example
run: |
zig build -Dandroid=true --verbose
zig build -Dandroid=true -Dcrash-on-exception --verbose
Expand All @@ -110,7 +110,7 @@ jobs:
# NOTE(jae): 2026-04-09
# Raylib example only runs on 0.16.X due to downstream dependencies
#
# - name: Build Raylib Example (Zig Stable)
# - name: Build Raylib Example
# run: zig build -Dandroid=true --verbose
# working-directory: examples/raylib

Expand Down Expand Up @@ -182,21 +182,21 @@ jobs:
with:
version: "master"

- name: Build Test (Zig Nightly)
run: zig build -Dandroid=true --verbose
working-directory: test/build
- name: Build Test
run: zig build --verbose
working-directory: test

- name: Build Minimal Example (Zig Nightly)
- name: Build Minimal Example
run: zig build -Dandroid=true --verbose
working-directory: examples/minimal

- name: Build SDL2 Example (Zig Nightly)
- name: Build SDL2 Example
run: zig build -Dandroid=true --verbose
working-directory: examples/sdl2

# note(jae): 2026-04-09
# Downstream packages for Raylib only support 0.16.X-dev right now.
- name: Build Raylib Example (Zig Nightly)
- name: Build Raylib Example
run: zig build -Dandroid=true --verbose
working-directory: examples/raylib
build-previous-stable:
Expand Down Expand Up @@ -232,11 +232,11 @@ jobs:
with:
version: ${{ needs.setup.outputs.zig-previous-stable-version }}

- name: Build Test (Zig Nightly)
run: zig build -Dandroid=true --verbose
working-directory: test/build
- name: Build Test
run: zig build --verbose
working-directory: test

- name: Build Minimal Example
- name: Build Minimal Example
run: zig build -Dandroid=true --verbose
working-directory: examples/minimal

Expand Down
1 change: 1 addition & 0 deletions build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
"build.zig.zon",
"src",
},
.minimum_zig_version = "0.16.0",
.fingerprint = 0x92bcb62d42fb2cee,
}
48 changes: 39 additions & 9 deletions src/androidbuild/Apk.zig
Original file line number Diff line number Diff line change
Expand Up @@ -512,19 +512,49 @@ fn doInstallApk(apk: *Apk) Allocator.Error!*Step.InstallFile {
while (iter.next()) |it| {
const module = it.value_ptr.*;
const root_source_file = module.root_source_file orelse continue;
const c_translate_target = module.resolved_target orelse continue;
if (!c_translate_target.result.abi.isAndroid()) continue;
switch (root_source_file) {
.generated => |gen| {
const step = gen.file.step;
if (step.id != .translate_c) {
continue;
}
const c_translate_target = module.resolved_target orelse continue;
if (!c_translate_target.result.abi.isAndroid()) {
continue;
switch (step.id) {
.translate_c => {
// Detect if using Translate-C vendored version
//
// NOTE(jae): 2026-04-29
// Longterm this will deprecated from Zig

const translate_c: *std.Build.Step.TranslateC = @fieldParentPtr("step", step);
translate_c.addIncludePath(.{ .cwd_relative = apk.ndk.include_path });
translate_c.addSystemIncludePath(.{ .cwd_relative = apk.getSystemIncludePath(c_translate_target) });
},
.run => {
// Detect if using Translate-C external dependency and make assumptions about the flags
// we can pass into it such as "isystem" and "-I"
//
// Name: https://codeberg.org/ziglang/translate-c/src/commit/71642ad0084d433f14b091a7b2b109f0be915dbb/build/Translator.zig#L89
// Imports: https://codeberg.org/ziglang/translate-c/src/commit/71642ad0084d433f14b091a7b2b109f0be915dbb/build/Translator.zig#L103-L104
if (std.mem.startsWith(u8, step.name, "translate-c ") and
(module.import_table.contains("c_builtins") and module.import_table.contains("helpers")))
{
const run: *std.Build.Step.Run = @fieldParentPtr("step", step);

const ndk_include_path: LazyPath = .{ .cwd_relative = apk.ndk.include_path };
const system_include_path: LazyPath = .{ .cwd_relative = apk.getSystemIncludePath(c_translate_target) };

// Exposes the system include path `path` to both translate-c and to `t.mod`.
// https://codeberg.org/ziglang/translate-c/src/commit/71642ad0084d433f14b091a7b2b109f0be915dbb/build/Translator.zig#L207-L211
module.addSystemIncludePath(system_include_path);
run.addPrefixedDirectoryArg("-isystem", system_include_path);

// Exposes the include path `path` to both translate-c and to `t.mod`.
// https://codeberg.org/ziglang/translate-c/src/commit/71642ad0084d433f14b091a7b2b109f0be915dbb/build/Translator.zig#L203-L206
module.addIncludePath(ndk_include_path);
run.addPrefixedDirectoryArg("-I", ndk_include_path);
}
},
else => continue,
}
const translate_c: *std.Build.Step.TranslateC = @fieldParentPtr("step", step);
translate_c.addIncludePath(.{ .cwd_relative = apk.ndk.include_path });
translate_c.addSystemIncludePath(.{ .cwd_relative = apk.getSystemIncludePath(c_translate_target) });
},
else => continue,
}
Expand Down
1 change: 1 addition & 0 deletions src/androidbuild/androidbuild.zig
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ pub fn standardTargets(b: *std.Build, target: ResolvedTarget) []ResolvedTarget {
// Seperated logic into "resolveTargets" so that consumers of this library can create this option themselves and use "b.lazyImport"
// See: https://github.com/silbinarywolf/zig-android-sdk/pull/82
const all_targets = b.option(bool, "android", "Build for all Android targets (x86, x86_64, aarch64, arm, etc)") orelse false;

return resolveTargets(b, .{
.default_target = target,
.all_targets = all_targets,
Expand Down
46 changes: 46 additions & 0 deletions test/build.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
const Build = @import("std").Build;
const builtin = @import("builtin");
const eql = @import("std").mem.eql;

/// Make sure this is a stable version of Zig
const is_latest_stable_zig = builtin.zig_version.pre == null and
builtin.zig_version.major == 0 and builtin.zig_version.minor >= 16;

pub fn build(b: *Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});

const all_step = b.step("all", "Run all tests");
b.default_step = all_step;

for (b.available_deps) |available_dep| {
const test_name, _ = available_dep;
const test_case_dep_step: *Build.Step = blk: {
if (is_latest_stable_zig) {
const dep = b.dependency(test_name, .{
.target = target,
.optimize = optimize,
.android = true,
});
break :blk dep.builder.default_step;
} else {
// Skip translate_c_dep as it requires Zig 0.16.0 stable as of 2026-04-29
if (eql(u8, test_name, "translate_c_dep")) {
continue;
}

// NOTE(jae): 2026-04-29
// Due to b.dependency() trying to always load Zig dependencies regardless
// of version requirements, we make other Zig versions invoke build manually
// so that ignoring dependency logic is respected.
const cmd = b.addSystemCommand(&.{ "zig", "build", "-Dandroid=true" });
cmd.setCwd(b.path(test_name));
cmd.expectExitCode(0);
break :blk &cmd.step;
}
};
const test_step = b.step(test_name, b.fmt("Run the '{s}' test", .{test_name}));
test_step.dependOn(test_case_dep_step);
all_step.dependOn(test_step);
}
}
11 changes: 11 additions & 0 deletions test/build.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.{
.name = .tests,
.version = "0.0.0",
.fingerprint = 0x1260fc5e4c176d8b,
.paths = .{""},
.dependencies = .{
.build = .{ .path = "build" },
.lazy_android = .{ .path = "lazy_android" },
.translate_c_dep = .{ .path = "translate_c_dep" },
},
}
109 changes: 62 additions & 47 deletions test/build/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,20 @@

const std = @import("std");
const builtin = @import("builtin");
const log = std.log.scoped(.build);

const android = @import("android");

/// Make sure this is a stable version of Zig
const is_latest_stable_zig = builtin.zig_version.pre == null and
builtin.zig_version.major == 0 and builtin.zig_version.minor >= 16;

pub fn build(b: *std.Build) void {
const exe_name: []const u8 = "build_test";
const root_target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const android_targets = android.standardTargets(b, root_target);

// NOTE(jae): 2026-04-12
// Run it *after* the "standardTargets" call
testLazyImportAndResolveTargets(b, root_target);

var root_target_single = [_]std.Build.ResolvedTarget{root_target};
const targets: []std.Build.ResolvedTarget = if (android_targets.len == 0)
root_target_single[0..]
Expand Down Expand Up @@ -46,77 +47,91 @@ pub fn build(b: *std.Build) void {
};

for (targets) |target| {
if (!target.result.abi.isAndroid()) {
std.debug.panic("For testing Android builds only. Target(s) should be Android not: {t}", .{target.result.abi});
}

const translate_c_vendored_mod = testTranslateCVendor(b, target, optimize) orelse return;

const app_module = b.createModule(.{
.target = target,
.optimize = optimize,
.root_source_file = b.path("src/build_test_main.zig"),
.imports = &.{
.{
.name = "translate_c_internal",
.module = translate_c_vendored_mod,
},
},
});

var exe: *std.Build.Step.Compile = if (target.result.abi.isAndroid()) b.addLibrary(.{
const libmain = b.addLibrary(.{
.name = "main",
.root_module = app_module,
.linkage = .dynamic,
}) else b.addExecutable(.{
.name = exe_name,
.root_module = app_module,
});

// if building as library for Android, add this target
// NOTE: Android has different CPU targets so you need to build a version of your
// code for x86, x86_64, arm, arm64 and more
if (target.result.abi.isAndroid()) {
const apk: *android.Apk = android_apk orelse @panic("Android APK should be initialized");
const android_dep = b.dependency("android", .{
.optimize = optimize,
.target = target,
});
exe.root_module.addImport("android", android_dep.module("android"));

apk.addArtifact(exe);
} else {
b.installArtifact(exe);

// If only 1 target, add "run" step
if (targets.len == 1) {
const run_step = b.step("run", "Run the application");
const run_cmd = b.addRunArtifact(exe);
run_step.dependOn(&run_cmd.step);
}
}
const apk: *android.Apk = android_apk orelse @panic("Android APK should be initialized");
const android_dep = b.dependency("android", .{
.optimize = optimize,
.target = target,
});
libmain.root_module.addImport("android", android_dep.module("android"));

apk.addArtifact(libmain);
}
if (android_apk) |apk| {
testInstallAndAddRunStep(b, apk);
}
}

/// Test calling lazyImport and then calling "resolveTargets"
///
/// PR: https://github.com/silbinarywolf/zig-android-sdk/pull/83
fn testLazyImportAndResolveTargets(b: *std.Build, root_target: std.Build.ResolvedTarget) void {
const all_android_targets = true;
const android_targets: []std.Build.ResolvedTarget = blk: {
if (all_android_targets or root_target.result.abi.isAndroid()) {
if (b.lazyImport(@This(), "lazy_android")) |lazy_android| {
break :blk lazy_android.resolveTargets(b, .{
.default_target = root_target,
.all_targets = true,
});
}
}
break :blk &[0]std.Build.ResolvedTarget{};
};
if (android_targets.len != 4) @panic("expected 'resolveTargets' it to return 4 Android targets");
/// Test the Translate-C vendored copy, this will eventually be deprecated and removed from Zig but for now exists in 0.16.X
fn testTranslateCVendor(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) ?*std.Build.Module {
const trans_c = b.addTranslateC(.{
.root_source_file = b.addWriteFiles().add("android_c.h",
\\#include <android/log.h>
),
.target = target,
.optimize = optimize,
});
return trans_c.createModule();
}

/// Test the Translate-C external dependency version
fn testTranslateCExternal(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) ?*std.Build.Module {
const translate_c_dep_name = if (comptime builtin.zig_version.major == 0 and builtin.zig_version.minor == 15)
"translate_c_previous_stable"
else
"translate_c_stable";
const translate_c_import = b.lazyImport(@This(), translate_c_dep_name) orelse return null;
const translate_c = b.lazyDependency(translate_c_dep_name, .{}) orelse return null;
const Translator = translate_c_import.Translator;

const trans_libandroid: Translator = .init(translate_c, .{
.c_source_file = b.addWriteFiles().add("android_c.h",
\\#include <android/log.h>
),
.target = target,
.optimize = optimize,
});
return trans_libandroid.mod;
}

/// Test the addLibraryFile functionality
///
/// Requested feature here: https://github.com/silbinarywolf/zig-android-sdk/issues/77
fn testAddLibraryFile(b: *std.Build, apk: *android.Apk) void {
if (!is_latest_stable_zig) {
return;
}

const vulkan_validation_dep = b.lazyDependency("vulkan_validation", .{}) orelse return;
apk.addLibraryFile(.arm64_v8a, vulkan_validation_dep.path("arm64-v8a/libVkLayer_khronos_validation.so"));
apk.addLibraryFile(.armeabi_v7a, vulkan_validation_dep.path("armeabi-v7a/libVkLayer_khronos_validation.so"));
apk.addLibraryFile(.x86, vulkan_validation_dep.path("x86/libVkLayer_khronos_validation.so"));
apk.addLibraryFile(.x86_64, vulkan_validation_dep.path("x86_64/libVkLayer_khronos_validation.so"));

log.info("testAddLibraryFile: add vulkan validation layers to APK", .{});
}

fn testInstallAndAddRunStep(b: *std.Build, apk: *android.Apk) void {
Expand Down
4 changes: 0 additions & 4 deletions test/build/build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@
.android = .{
.path = "../..",
},
.lazy_android = .{
.path = "../..",
.lazy = true,
},
.vulkan_validation = .{
.url = "https://github.com/KhronosGroup/Vulkan-ValidationLayers/releases/download/vulkan-sdk-1.4.341.0/android-binaries-1.4.341.0.zip",
.hash = "N-V-__8AABTXlAV0z_BGl5-lZeOEm_d2gHEhExT2qjxMqQ72",
Expand Down
5 changes: 5 additions & 0 deletions test/build/src/build_test_main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ const builtin = @import("builtin");

const android = @import("android");

comptime {
// For vendored translate-c usage, validate at compile-time that this symbol exists
_ = @import("translate_c_internal").__android_log_write;
}

const androidbind = @import("android-bind.zig");

/// custom standard options for Android
Expand Down
Loading
Loading