Skip to content

Raylib not loading files from asset folder. #86

Closed

Description

@stark26583

I used the addassetsdirectory functions to add a asset directory. I don't know if this is a raylib issue or zig-android-sdk issue but. for some reason the raylib can't find the file in the assets directory. I looked into the source code of raylib in rcore_android.c and there isn't seem to be any issue with the raylib side. So I cant find what is wrong. please if this is a issue please fix it. or if I am doing any mistake please can you point me and help solve this problem. Thank you.

this is the final apk structure:

Archive:  first.apk
  Length      Date    Time    Name
---------  ---------- -----   ----
     2964  1980-01-01 00:00   AndroidManifest.xml
  1497484  1980-01-01 00:00   assets/BungeeSpice-Regular.ttf
     4508  2026-04-20 15:03   classes.dex
   488024  2026-04-18 18:21   lib/arm64-v8a/libfirst.so
     7028  1980-01-01 00:00   res/mipmap/icon.png
      804  1980-01-01 00:00   resources.arsc
      569  2026-04-20 15:03   META-INF/DEFAULT.SF
     2101  2026-04-20 15:03   META-INF/DEFAULT.RSA
      461  2026-04-20 15:03   META-INF/MANIFEST.MF
---------                     -------
  2003943                     9 files

this is the log:

04-20 15:03:38.588  2627  2627 E com.stark.first: Unknown bits set in runtime_flags: 0x40000000
04-20 15:03:38.588  2627  2627 I com.stark.first: Using CollectorTypeCMC GC.
04-20 15:03:38.700  2627  2627 I com.stark.first: AssetManager2(0xb400007d771a5728) locale list changing from [] to [en-GB]
04-20 15:03:38.719  2627  2627 I com.stark.first: AssetManager2(0xb400007d2f3fd328) locale list changing from [] to [en-GB]
04-20 15:03:38.834  2627  2799 I raylib  : TIMER: Target time per frame: 5.000 milliseconds
04-20 15:03:38.834  2627  2799 I raylib  : Initializing raylib 6.0
04-20 15:03:38.834  2627  2799 I raylib  : Platform backend: ANDROID
04-20 15:03:38.834  2627  2799 I raylib  : Supported raylib modules:
04-20 15:03:38.834  2627  2799 I raylib  :     > rcore:..... loaded (mandatory)
04-20 15:03:38.834  2627  2799 I raylib  :     > rlgl:...... loaded (mandatory)
04-20 15:03:38.834  2627  2799 I raylib  :     > rshapes:... loaded (optional)
04-20 15:03:38.834  2627  2799 I raylib  :     > rtextures:. loaded (optional)
04-20 15:03:38.834  2627  2799 I raylib  :     > rtext:..... loaded (optional)
04-20 15:03:38.834  2627  2799 I raylib  :     > rmodels:... loaded (optional)
04-20 15:03:38.834  2627  2799 I raylib  :     > raudio:.... loaded (optional)
04-20 15:03:38.834  2627  2799 I raylib  : ANDROID: Window orientation set as portrait
04-20 15:03:38.834  2627  2799 W raylib  : ANDROID: Window orientation changed to portrait
04-20 15:03:38.834  2627  2799 I raylib  : PLATFORM: ANDROID: Initialized successfully
04-20 15:03:38.848  2627  2627 W com.stark.first: AIBinder_linkToDeath is being called with a non-null cookie and no onUnlink callback set. This might not be i
ntended. AIBinder_DeathRecipient_setOnUnlinked should be called first.
04-20 15:03:38.920  2627  2799 I raylib  : DISPLAY: Upscaling required: Screen size (0x0) smaller than display size (1080x2412)
04-20 15:03:38.924  2627  2799 I raylib  : DISPLAY: Device initialized successfully
04-20 15:03:38.924  2627  2799 I raylib  :     > Display size: 1080 x 2412
04-20 15:03:38.924  2627  2799 I raylib  :     > Screen size:  1080 x 2412
04-20 15:03:38.924  2627  2799 I raylib  :     > Render size:  1080 x 2412
04-20 15:03:38.924  2627  2799 I raylib  :     > Viewport offsets: 0, 0
04-20 15:03:38.924  2627  2799 I raylib  : GL: Supported extensions count: 118
04-20 15:03:38.924  2627  2799 I raylib  : GL: OpenGL device information:
04-20 15:03:38.924  2627  2799 I raylib  :     > Vendor:   Qualcomm
04-20 15:03:38.924  2627  2799 I raylib  :     > Renderer: Adreno (TM) 740
04-20 15:03:38.924  2627  2799 I raylib  :     > Version:  OpenGL ES 3.2 V@0676.76.1 (GIT@bad34dcf83, I1064ae0a1f, 1764326394) (Date:11/28/25)
04-20 15:03:38.924  2627  2799 I raylib  :     > GLSL:     OpenGL ES GLSL ES 3.20
04-20 15:03:38.924  2627  2799 I raylib  : GL: VAO extension detected, VAO functions loaded successfully
04-20 15:03:38.924  2627  2799 I raylib  : GL: NPOT textures extension detected, full NPOT textures supported
04-20 15:03:38.924  2627  2799 I raylib  : GL: DXT compressed textures supported
04-20 15:03:38.924  2627  2799 I raylib  : GL: ETC1 compressed textures supported
04-20 15:03:38.924  2627  2799 I raylib  : GL: ASTC compressed textures supported
04-20 15:03:38.924  2627  2799 I raylib  : TEXTURE: [ID 1] Texture loaded successfully (1x1 | R8G8B8A8 | 1 mipmaps)
04-20 15:03:38.925  2627  2799 I raylib  : TEXTURE: [ID 1] Default texture loaded successfully
04-20 15:03:38.927  2627  2799 I raylib  : SHADER: [ID 1] Vertex shader compiled successfully
04-20 15:03:38.927  2627  2799 I raylib  : SHADER: [ID 2] Fragment shader compiled successfully
04-20 15:03:38.928  2627  2799 I raylib  : SHADER: [ID 3] Program shader loaded successfully
04-20 15:03:38.928  2627  2799 I raylib  : SHADER: [ID 3] Default shader loaded successfully
04-20 15:03:38.928  2627  2799 I raylib  : RLGL: Render batch vertex buffers loaded successfully in RAM (CPU)
04-20 15:03:38.931  2627  2799 I raylib  : RLGL: Render batch vertex buffers loaded successfully in VRAM (GPU)
04-20 15:03:38.933  2627  2799 I raylib  : RLGL: Default OpenGL state initialized successfully
04-20 15:03:38.933  2627  2799 I raylib  : TEXTURE: [ID 2] Texture loaded successfully (128x128 | GRAY_ALPHA | 1 mipmaps)
04-20 15:03:38.933  2627  2799 I raylib  : FONT: Default font loaded successfully (224 glyphs)
04-20 15:03:38.933  2627  2799 I raylib  : TEXTURE: [ID 3] Texture loaded successfully (1x1 | R8G8B8A8 | 1 mipmaps)
04-20 15:03:38.933  2627  2799 I raylib  : TEXTURE: [ID 3] Default texture loaded successfully
04-20 15:03:38.933  2627  2799 I raylib  : SHADER: [ID 4] Vertex shader compiled successfully
04-20 15:03:38.933  2627  2799 I raylib  : SHADER: [ID 5] Fragment shader compiled successfully
04-20 15:03:38.934  2627  2799 I raylib  : SHADER: [ID 6] Program shader loaded successfully
04-20 15:03:38.934  2627  2799 I raylib  : SHADER: [ID 6] Default shader loaded successfully
04-20 15:03:38.934  2627  2799 I raylib  : RLGL: Render batch vertex buffers loaded successfully in RAM (CPU)
04-20 15:03:38.934  2627  2799 I raylib  : RLGL: Render batch vertex buffers loaded successfully in VRAM (GPU)
04-20 15:03:38.934  2627  2799 I raylib  : RLGL: Default OpenGL state initialized successfully
04-20 15:03:38.934  2627  2799 I raylib  : SYSTEM: Working Directory: /
04-20 15:03:38.934  2627  2799 W raylib  : FILEIO: [BungeeSpice-Regular.ttf] Failed to open file
04-20 15:03:38.934  2627  2799 I raylib  : TEXTURE: [ID 2] Unloaded texture data from VRAM (GPU)
04-20 15:03:38.934  2627  2799 I raylib  : SHADER: [ID 6] Default shader unloaded successfully
04-20 15:03:38.934  2627  2799 I raylib  : TEXTURE: [ID 3] Default texture unloaded successfully
04-20 15:03:38.939  2627  2799 I raylib  : Window closed successfully
04-20 15:03:38.939  2627  2799 E com.stark.first: LoadFont

this is my main.zig:

const std = @import("std");
const Engine = @import("engine");
const RL = Engine.rl;
const GUI = Engine.gui;

const builtin = @import("builtin");

pub fn main() !void {
    RL.setTargetFPS(200);
    Engine.init_window(1200, 700, "first");
    defer Engine.close_window();

    const font = if (!builtin.abi.isAndroid()) try RL.loadFontEx("assets/BungeeSpice-Regular.ttf", 100, null) else try RL.loadFontEx("BungeeSpice-Regular.ttf", 100, null);
    defer font.unload();

    GUI.init(font);

    while (!RL.windowShouldClose()) {
        if (RL.isKeyPressed(.back)) break;
        RL.beginDrawing();
        defer RL.endDrawing();

        RL.clearBackground(.gold);
        var buff: [512]u8 = undefined;
        const text = try std.fmt.bufPrintZ(&buff, "FPS: {d}", .{RL.getFPS()});
        RL.drawTextEx(font, text, .init(12, 12), 30, 1, .green);
    }
}

const android = Engine.android;
pub const std_options: std.Options = if (builtin.abi.isAndroid())
    .{
        .logFn = android.logFn,
    }
else
    .{};

comptime {
    if (builtin.abi.isAndroid()) {
        @export(&androidMain, .{ .name = "main" });
        @export(&raylibFileOpen, .{ .name = "__real_fopen" });
    }
}
fn raylibFileOpen(filename: [*c]const u8, modes: [*c]const u8) callconv(.c) ?*anyopaque {
    return @import("std").c.fopen(filename, modes);
}

fn androidMain() callconv(.c) c_int {
    main() catch |err| {
        std.log.err("{t}", .{err});
        if (@errorReturnTrace()) |trace| std.debug.dumpStackTrace(trace);
        return 1;
    };
    return 0;
}

Activity

  1. silbinarywolf commented on Apr 21, 2026

    @silbinarywolf
    Owner

    It is kind of a Raylib / Zig combination issue. Raylib changed its library loading behaviour recently-ish as I discovered in this PR here.

    Looks like Raylib on Android now requires linker flags:

    # Wrap fopen at link time so all code (including third-party libs) goes
    # through __wrap_fopen, which handles Android APK asset loading
    LDFLAGS += -Wl,--wrap=fopen

    https://github.com/raysan5/raylib/blob/master/src/Makefile#L617-L619

    Because we can't add these linker flags on the Zig side, I'm actually not sure what we can do to resolve this issue other than putting in the work for the Zig Android SDK to allow us to use its linker instead when building an APK.

    We need a way to tell Zig that all fopen calls should call __wrap_fopen.

  2. silbinarywolf commented on Apr 21, 2026

    @silbinarywolf
    Owner

    Someone put up a gist here so maybe the fix needs to look more like this on the Zig-side:

    extern "c" fn __wrap_fopen(filename: [*c]const u8, modes: [*c]const u8) callconv(.c) ?*anyopaque;
    
    // Zig version used to write was 0.16.0
    // Define dlsym and RTLD_NEXT to be able to call system fopen as I am overriding it bellow
    // https://pubs.opengroup.org/onlinepubs/009604299/functions/dlsym.html
    extern "c" fn dlsym(handle: ?*anyopaque, symbol: [*c]const u8) ?*anyopaque;
    const RTLD_NEXT = @as(?*anyopaque, @ptrFromInt(@as(usize, @bitCast(@as(isize, -1)))));
    
    // Override fopen to call __wrap_fopen
    export fn fopen(filename: [*c]const u8, modes: [*c]const u8) callconv(.c) ?*anyopaque {
        return __wrap_fopen(filename, modes);
    }
    
    // Implement __real_fopen as Raylib needs it to open files that are not inside assets folder
    export fn __real_fopen(filename: [*c]const u8, modes: [*c]const u8) callconv(.c) ?*anyopaque {
        const real_fopen_ptr = dlsym(RTLD_NEXT, "fopen") orelse return null;
        const real_fopen: *const fn ([*c]const u8, [*c]const u8) callconv(.c) ?*anyopaque = @ptrCast(@alignCast(real_fopen_ptr));
    
        return real_fopen(filename, modes);
    }

    https://gist.github.com/maiconpintoabreu/f5eb68d467ba6105256daf03e3ede51c

  3. stark26583 commented on Apr 21, 2026

    @stark26583
    Author

    Thanks for reply. after trying to adapt this in a cross platform way it ended up like this:

    pub const std_options: std.Options = if (builtin.abi.isAndroid())
        .{
            .logFn = android.logFn,
        }
    else
        .{};
    
    comptime {
        if (builtin.abi.isAndroid()) {
            @export(&androidMain, .{ .name = "main" });
            @export(&fopen, .{ .name = "fopen" });
            @export(&__real_fopen, .{ .name = "__real_fopen" });
        }
    }
    // fn raylibFileOpen(filename: [*c]const u8, modes: [*c]const u8) callconv(.c) ?*anyopaque {
    //     return @import("std").c.fopen(filename, modes);
    // }
    
    fn androidMain() callconv(.c) c_int {
        main() catch |err| {
            std.log.err("{t}", .{err});
            if (@errorReturnTrace()) |trace| std.debug.dumpStackTrace(trace);
            return 1;
        };
        return 0;
    }
    
    const fun = if (builtin.abi.isAndroid()) struct {
        pub extern "c" fn __wrap_fopen(filename: [*c]const u8, modes: [*c]const u8) callconv(.c) ?*anyopaque;
    
        // Zig version used to write was 0.16.0
        // Define dlsym and RTLD_NEXT to be able to call system fopen as I am overriding it bellow
        // https://pubs.opengroup.org/onlinepubs/009604299/functions/dlsym.html
        pub extern "c" fn dlsym(handle: ?*anyopaque, symbol: [*c]const u8) ?*anyopaque;
    } else void;
    
    const RTLD_NEXT = @as(?*anyopaque, @ptrFromInt(@as(usize, @bitCast(@as(isize, -1)))));
    
    // Override fopen to call __wrap_fopen
    fn fopen(filename: [*c]const u8, modes: [*c]const u8) callconv(.c) ?*anyopaque {
        return fun.__wrap_fopen(filename, modes);
    }
    
    // Implement __real_fopen as Raylib needs it to open files that are not inside assets folder
    fn __real_fopen(filename: [*c]const u8, modes: [*c]const u8) callconv(.c) ?*anyopaque {
        const real_fopen_ptr = fun.dlsym(RTLD_NEXT, "fopen") orelse return null;
        const real_fopen: *const fn ([*c]const u8, [*c]const u8) callconv(.c) ?*anyopaque = @ptrCast(@alignCast(real_fopen_ptr));
    
        return real_fopen(filename, modes);
    }
    

    it works now on android and desktop but is very bulky for a simple app. will this issue get updated in this sdk or is this is way to do it from now? and is there any kind of build step where i could have just a file with simple main function and this extra code be added at build time to make it cross platform?

  4. silbinarywolf commented on Apr 21, 2026

    @silbinarywolf
    Owner

    Yeah agreed, I think the proper fix would be making the above code workaround belong in the Zig Raylib repo here:
    https://github.com/raylib-zig/raylib-zig

    Maybe consider raising an issue on that repository? But if they don't want to take it on, then the patch can just stay in this repos example.

  5. silbinarywolf commented on Apr 23, 2026

    @silbinarywolf
    Owner

    @stark26583 I've at least updated the Raylib example to include loading asset files and tested it with the required fixes:
    #89

  6. stark26583 commented on Apr 23, 2026

    @stark26583
    Author

    Thanks for your work.

  7. added a commit that references this issue on Apr 25, 2026
    a73fc01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions