From 950c064448a7ef1d82b2d01114dd6d4923bb1d04 Mon Sep 17 00:00:00 2001 From: ghera Date: Mon, 2 Mar 2026 12:18:04 +0100 Subject: [PATCH] [rcore][android] Replace `android_fopen()` with linker `--wrap=fopen` (#5605) * ANDROID: replace android_fopen with linker --wrap=fopen * ANDROID: add --wrap=fopen linker flag to src/Makefile --- src/CMakeLists.txt | 6 ++++++ src/Makefile | 3 +++ src/platforms/rcore_android.c | 31 ++++++++++++------------------- src/raudio.c | 5 ----- 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 76c985969..dad7dd582 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -75,6 +75,12 @@ if (${PLATFORM} MATCHES "Web") endif() endif() +if (${PLATFORM} MATCHES "Android") + # Wrap fopen at link time so all code (including third-party libs) goes + # through __wrap_fopen, which handles Android APK asset loading + target_link_options(raylib INTERFACE -Wl,--wrap=fopen) +endif() + set_target_properties(raylib PROPERTIES PUBLIC_HEADER "${raylib_public_headers}" VERSION ${PROJECT_VERSION} diff --git a/src/Makefile b/src/Makefile index 84f44e10a..e53514701 100644 --- a/src/Makefile +++ b/src/Makefile @@ -614,6 +614,9 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID) LDFLAGS += -Lsrc # Avoid unresolved symbol pointing to external main() LDFLAGS += -Wl,-undefined,dynamic_lookup + # 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 endif # Define libraries required on linking: LDLIBS diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c index d7fdca403..9cf3b543b 100644 --- a/src/platforms/rcore_android.c +++ b/src/platforms/rcore_android.c @@ -275,12 +275,12 @@ static int android_write(void *cookie, const char *buf, int size); static fpos_t android_seek(void *cookie, fpos_t offset, int whence); static int android_close(void *cookie); -FILE *android_fopen(const char *fileName, const char *mode); // Replacement for fopen() -> Read-only! +FILE *__real_fopen(const char *fileName, const char *mode); // Real fopen, provided by the linker (--wrap=fopen) +FILE *__wrap_fopen(const char *fileName, const char *mode); // Replacement for fopen() + FILE *funopen(const void *cookie, int (*readfn)(void *, char *, int), int (*writefn)(void *, const char *, int), fpos_t (*seekfn)(void *, fpos_t, int), int (*closefn)(void *)); -#define fopen(name, mode) android_fopen(name, mode) - //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- @@ -1524,25 +1524,20 @@ static void SetupFramebuffer(int width, int height) } } -// Replacement for fopen() +// Replacement for fopen(), used as linker wrap entry point (-Wl,--wrap=fopen) // REF: https://developer.android.com/ndk/reference/group/asset -FILE *android_fopen(const char *fileName, const char *mode) +FILE *__wrap_fopen(const char *fileName, const char *mode) { FILE *file = NULL; - + + // NOTE: AAsset provides access to read-only asset, write operations use regular fopen if (mode[0] == 'w') { - // NOTE: fopen() is mapped to android_fopen() that only grants read access to - // assets directory through AAssetManager but it could be required to write data - // using the standard stdio FILE access functions - // REF: https://stackoverflow.com/questions/11294487/android-writing-saving-files-from-native-code-only - #undef fopen - file = fopen(TextFormat("%s/%s", platform.app->activity->internalDataPath, fileName), mode); - #define fopen(name, mode) android_fopen(name, mode) + file = __real_fopen(TextFormat("%s/%s", platform.app->activity->internalDataPath, fileName), mode); + if (file == NULL) file = __real_fopen(fileName, mode); } else { - // NOTE: AAsset provides access to read-only asset AAsset *asset = AAssetManager_open(platform.app->activity->assetManager, fileName, AASSET_MODE_UNKNOWN); if (asset != NULL) @@ -1552,14 +1547,12 @@ FILE *android_fopen(const char *fileName, const char *mode) } else { - #undef fopen // Just do a regular open if file is not found in the assets - file = fopen(TextFormat("%s/%s", platform.app->activity->internalDataPath, fileName), mode); - if (file == NULL) file = fopen(fileName, mode); - #define fopen(name, mode) android_fopen(name, mode) + file = __real_fopen(TextFormat("%s/%s", platform.app->activity->internalDataPath, fileName), mode); + if (file == NULL) file = __real_fopen(fileName, mode); } } - + return file; } diff --git a/src/raudio.c b/src/raudio.c index ec2b474d1..afe0a7814 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -180,11 +180,6 @@ typedef struct tagBITMAPINFOHEADER { #include // Required for: FILE, fopen(), fclose(), fread() #include // Required for: strcmp() [Used in IsFileExtension(), LoadWaveFromMemory(), LoadMusicStreamFromMemory()] -#if defined(PLATFORM_ANDROID) - FILE *android_fopen(const char *fileName, const char *mode); - #define fopen(name, mode) android_fopen(name, mode) -#endif - #if defined(RAUDIO_STANDALONE) #ifndef TRACELOG #define TRACELOG(level, ...) printf(__VA_ARGS__)