Skip to content
Merged
159 changes: 122 additions & 37 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,44 +11,87 @@ concurrency:
group: ${{ github.head_ref || github.run_id }}-${{ github.actor }}
cancel-in-progress: true

env:
CI_JAVA_VERSION: 17
# 35.0.0 = Android 15
CI_ANDROID_SDK: "tools platform-tools platforms;android-35 build-tools;35.0.0 ndk;29.0.13113456"
CI_ZIG_PREVIOUS_STABLE_VERSION: "0.14.0"
CI_ZIG_STABLE_VERSION: "0.15.1"

jobs:
build:
name: Build
# NOTE(jae): 2026-02-01
# Run a Zig format check before any other steps on latest Zig stable
format:
name: zig fmt --check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Setup Zig
uses: mlugg/setup-zig@v2

# Run AST check
#
# Specifically ignore ./src/android as the runtime has different Zig version for compile-time features
# like @EnumLiteral
- name: AST Check (src/androidbuild)
run: |
zig fmt --ast-check ./build.zig
zig fmt --ast-check ./src/androidbuild

# Run format check
- name: Zig Format Check
run: zig fmt --check .

# https://stackoverflow.com/questions/73797254/environment-variables-in-github-actions
setup:
name: setup environment variables as outputs
needs: [format]
runs-on: ubuntu-latest
steps:
- run: echo "null"
outputs:
java-version: ${{ env.CI_JAVA_VERSION }}
android-sdk: ${{ env.CI_ANDROID_SDK }}
zig-stable-version: ${{ env.CI_ZIG_STABLE_VERSION }}
zig-previous-stable-version: ${{ env.CI_ZIG_PREVIOUS_STABLE_VERSION }}


build-stable:
name: Build Zig Stable
needs: [setup]
runs-on: ${{matrix.os}}
strategy:
max-parallel: 1
matrix:
include:
- os: "ubuntu-latest"
- os: "windows-latest"
- os: "macos-14" # arm64 as per table: https://github.com/actions/runner-images/blob/8a1eeaf6ac70c66f675a04078d1a7222edd42008/README.md#available-images

runs-on: ${{matrix.os}}

steps:
- uses: actions/checkout@v6

- name: Set up JDK 17
# Setup Java and Android SDK
- name: Set up JDK ${{ needs.setup.outputs.java-version }}
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'temurin'
java-version: ${{ needs.setup.outputs.java-version }}
distribution: "temurin"

- name: Setup Android SDK
uses: android-actions/setup-android@v3
with:
# 35.0.0 = Android 15
packages: 'tools platform-tools platforms;android-35 build-tools;35.0.0 ndk;29.0.13113456'
packages: ${{ needs.setup.outputs.android-sdk }}

#
# Stable Zig Builds
#

- name: Setup Zig Stable (0.15.2)
# Setup Zig version and run examples
- name: Setup Zig
# note(jae): 2024-09-15
# Uses download mirror first as preferred by Zig Foundation
# see: https://ziglang.org/news/migrate-to-self-hosting/
uses: mlugg/setup-zig@v2
with:
version: "0.15.2"
version: ${{ needs.setup.outputs.zig-stable-version }}

- name: Build Minimal Example (Zig Stable)
run: zig build -Dandroid=true --verbose
Expand Down Expand Up @@ -99,32 +142,34 @@ jobs:
# adb shell monkey --kill-process-after-error --monitor-native-crashes --pct-touch 100 -p com.zig.sdl2 --throttle 1000 -v 2
# working-directory: examples/sdl2

#
# Previous Stable Zig Build
#
build-nightly:
name: Build Zig Nightly
needs: [setup]
runs-on: ${{matrix.os}}
strategy:
max-parallel: 1
matrix:
include:
- os: "ubuntu-latest"
- os: "windows-latest"
- os: "macos-14" # arm64 as per table: https://github.com/actions/runner-images/blob/8a1eeaf6ac70c66f675a04078d1a7222edd42008/README.md#available-images

steps:
- uses: actions/checkout@v6

- name: Setup Zig Previous Stable (0.14.0)
uses: mlugg/setup-zig@v2
# Setup Java and Android SDK
- name: Set up JDK ${{ needs.setup.outputs.java-version }}
uses: actions/setup-java@v5
with:
version: "0.14.0"

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

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

# "Raylib requires zig version 0.15.1" error occurs
# - name: Build Raylib Example (Zig Previous Stable)
# run: zig build -Dandroid=true --verbose
# working-directory: examples/raylib
java-version: ${{ needs.setup.outputs.java-version }}
distribution: "temurin"

#
# Nightly Zig Builds
#
- name: Setup Android SDK
uses: android-actions/setup-android@v3
with:
packages: ${{ needs.setup.outputs.android-sdk }}

# Setup Zig version and run examples
- name: Setup Zig Nightly
uses: mlugg/setup-zig@v2
with:
Expand All @@ -144,3 +189,43 @@ jobs:
# - name: Build Raylib Example (Zig Nightly)
# run: zig build -Dandroid=true --verbose
# working-directory: examples/raylib
build-previous-stable:
name: Build Zig Previous
needs: [setup]
runs-on: ${{matrix.os}}
strategy:
max-parallel: 1
matrix:
include:
- os: "ubuntu-latest"
- os: "windows-latest"
- os: "macos-14" # arm64 as per table: https://github.com/actions/runner-images/blob/8a1eeaf6ac70c66f675a04078d1a7222edd42008/README.md#available-images

steps:
- uses: actions/checkout@v6

# Setup Java and Android SDK
- name: Set up JDK ${{ needs.setup.outputs.java-version }}
uses: actions/setup-java@v5
with:
java-version: ${{ needs.setup.outputs.java-version }}
distribution: "temurin"

- name: Setup Android SDK
uses: android-actions/setup-android@v3
with:
packages: ${{ needs.setup.outputs.android-sdk }}

# Setup Zig version and run examples
- name: Setup Zig
uses: mlugg/setup-zig@v2
with:
version: ${{ needs.setup.outputs.zig-previous-stable-version }}

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

- name: Build SDL2 Example
run: zig build -Dandroid=true --verbose
working-directory: examples/sdl2
48 changes: 17 additions & 31 deletions examples/raylib/build.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const android = @import("android");
const std = @import("std");
const android = @import("android");
const LinkMode = std.builtin.LinkMode;

const exe_name = "raylib";

Expand Down Expand Up @@ -33,64 +34,49 @@ pub fn build(b: *std.Build) void {
};

for (targets) |target| {
const lib_mod = b.createModule(.{
const app = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
});
const lib = b.addLibrary(.{
.linkage = .dynamic,
.name = exe_name,
.root_module = lib_mod,
// note(jae): 2025-09-19
// Force use_llvm = true, to workaround issue in Zig 0.15.1 where an error occurs with
// - step: compile lib raylib Debug x86_64-linux-android failure
// panic: "TODO unhandled compression scheme"
.use_llvm = if (target.result.abi.isAndroid()) true else null,
});
b.installArtifact(lib);

const raylib_dep = if (android_apk) |apk|
b.dependency("raylib_zig", .{
.target = target,
.optimize = optimize,
.android_api_version = @as([]const u8, b.fmt("{}", .{@intFromEnum(apk.api_level)})),
.android_ndk = @as([]const u8, apk.ndk.path),
// NOTE(jae): 2025-09-19
// Avoid compilation errors on Linux systems that don't have 'wayland-scanner'
// ie.
// $ zig build -Dandroid=true --verbose
// `wayland-scanner` may not be installed on the system.
// You can switch to X11 in your `build.zig` by changing `Options.linux_display_backend`
.linux_display_backend = .X11, // Avoid build issues on Linux systems
})
else
b.dependency("raylib_zig", .{
.target = target,
.optimize = optimize,
.linkage = std.builtin.LinkMode.dynamic,
.linkage = LinkMode.dynamic,
});

const raylib_artifact = raylib_dep.artifact("raylib");
lib.root_module.linkLibrary(raylib_artifact);
const raylib_mod = raylib_dep.module("raylib");
lib.root_module.addImport("raylib", raylib_mod);
app.linkLibrary(raylib_dep.artifact("raylib"));
app.addImport("raylib", raylib_dep.module("raylib"));

if (android_apk) |apk| {
const android_dep = b.dependency("android", .{
.target = target,
.optimize = optimize,
});
lib.root_module.addImport("android", android_dep.module("android"));
lib.root_module.linkSystemLibrary("android", .{});
app.addImport("android", android_dep.module("android"));
app.linkSystemLibrary("android", .{});

const native_app_glue_dir: std.Build.LazyPath = .{ .cwd_relative = b.fmt("{s}/sources/android/native_app_glue", .{apk.ndk.path}) };
lib.root_module.addCSourceFile(.{ .file = native_app_glue_dir.path(b, "android_native_app_glue.c") });
lib.root_module.addIncludePath(native_app_glue_dir);
apk.addArtifact(lib);
app.addCSourceFile(.{ .file = native_app_glue_dir.path(b, "android_native_app_glue.c") });
app.addIncludePath(native_app_glue_dir);

apk.addArtifact(b.addLibrary(.{
.linkage = .dynamic,
.name = exe_name,
.root_module = app,
}));
} else {
const exe = b.addExecutable(.{ .name = exe_name, .root_module = lib_mod });
const exe = b.addExecutable(.{ .name = exe_name, .root_module = app });
b.installArtifact(exe);

const run_exe = b.addRunArtifact(exe);
Expand Down
4 changes: 2 additions & 2 deletions examples/raylib/build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
.dependencies = .{
.android = .{ .path = "../.." },
.raylib_zig = .{
.url = "git+https://github.com/raylib-zig/raylib-zig#d64fc43f38949231dc7d6f1c016db8fcae858b8c",
.hash = "raylib_zig-5.6.0-dev-KE8REDc2BQCri1t11guC1tZA-Luc7NuVeml_59LSELLe",
.url = "git+https://github.com/raylib-zig/raylib-zig#cd71c85d571027ac8033357f83b124ee051825b3",
.hash = "raylib_zig-5.6.0-dev-KE8REENOBQC-m5nK7M2b5aKSIubJPbPLUYcRhT7aT3RN",
},
},
.paths = .{
Expand Down
16 changes: 14 additions & 2 deletions src/androidbuild/apk.zig
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub fn create(sdk: *Sdk, options: Options) *Apk {
.artifacts = .empty,
.java_files = .empty,
.resources = .empty,
.assets = .empty
.assets = .empty,
};
return apk;
}
Expand Down Expand Up @@ -362,7 +362,7 @@ fn doInstallApk(apk: *Apk) std.mem.Allocator.Error!*Step.InstallFile {
.directory => |asset_dir| {
aapt2link.addArg("-A");
aapt2link.addDirectoryArg(asset_dir.source);
}
},
}
}

Expand Down Expand Up @@ -450,6 +450,18 @@ fn doInstallApk(apk: *Apk) std.mem.Allocator.Error!*Step.InstallFile {
@panic(b.fmt("artifact[{d}] has no 'target' set", .{artifact_index}));
};

// NOTE(jae): 2026-02-01
// If not explicitly set in users build, default to using LLVM and LLD for Android builds
// as that's the same toolchain that the Android SDK uses.
//
// This also can resolve issues with Zigs linker not yet supporting certain compression schemes/etc
if (artifact.use_llvm == null) {
artifact.use_llvm = true;
}
if (artifact.use_lld == null) {
artifact.use_lld = true;
}

// https://developer.android.com/ndk/guides/abis#native-code-in-app-packages
const so_dir: []const u8 = switch (target.result.cpu.arch) {
.aarch64 => "arm64-v8a",
Expand Down