SDL: Fix SDL_MAIN_USE_CALLBACKS with Android, introduce SDL_MAIN_EXPORTED

From 33366b0a4ecc190efb9dcf2607dfb50958aa2aeb Mon Sep 17 00:00:00 2001
From: Daniel Gibson <[EMAIL REDACTED]>
Date: Fri, 11 Oct 2024 23:04:00 +0200
Subject: [PATCH] Fix SDL_MAIN_USE_CALLBACKS with Android, introduce
 SDL_MAIN_EXPORTED

My simplification of the conditions for including SDL_main_impl.h
had one problem: I forgot that SDL_main_impl.h must be included
even on Android when SDL_MAIN_USE_CALLBACKS is used, because then a
SDL_main() function that makes sure the callbacks get called is needed,
and that function is implemented in SDL_main_impl.h

But OTOH, even when SDL_MAIN_USE_CALLBACKS is used, SDL_main_impl.h
should not implement a standard `int main(...)` function on Android
(because there the SDL-using native code is compiled as a library and
 the entry point is in SDLActivity.java, which calls SDL_main()
 in said library).

So the check for platforms that don't have *any* native main function
but just SDL_main() called from the outside should be handled in
SDL_main_impl.h, so both the normal and the callback case can avoid
generating a standard main() in the same way.
To do this, SDL_MAIN_EXPORTED is defined for platforms like Android,
where the real entry point (main() function) is outside of the code
that uses SDL, so
- SDL_main() must be visibly exported with SDL_DECLSPEC, so the outside
  code can call it
- SDL_main_impl.h must not implement a "real" main() function

Another small change based on this is defining SDLMAIN_DECLSPEC
at a more general place.

If another platform like Android (where the entry point is somewhere
else entirely, possibly implemented in a different programming language)
turns up, defining SDL_MAIN_NEEDED (so the users main() is renamed
to SDL_main()) and SDL_MAIN_EXPORTED should be all that's needed on the
SDL_main.h side - and if not then at least the implementation is
cleaner and clearer now, IMHO.

fixes #11162
---
 include/SDL3/SDL_main.h      | 29 +++++++++++++++++------------
 include/SDL3/SDL_main_impl.h |  7 ++++---
 2 files changed, 21 insertions(+), 15 deletions(-)

diff --git a/include/SDL3/SDL_main.h b/include/SDL3/SDL_main.h
index 6160e5e364e61..52fc8150ff751 100644
--- a/include/SDL3/SDL_main.h
+++ b/include/SDL3/SDL_main.h
@@ -86,8 +86,14 @@
          */
         #define SDL_MAIN_NEEDED
 
-        /* We need to export SDL_main so it can be launched from Java */
-        #define SDLMAIN_DECLSPEC    SDL_DECLSPEC
+        /* As this is launched from Java, the real entry point (main() function)
+           is outside of the the binary built from this code.
+           This define makes sure that, unlike on other platforms, SDL_main.h
+           and SDL_main_impl.h export an `SDL_main()` function (to be called
+           from Java), but don't implement a native `int main(int argc, char* argv[])`
+           or similar.
+         */
+        #define SDL_MAIN_EXPORTED
 
     #elif defined(SDL_PLATFORM_EMSCRIPTEN)
         /* On Emscripten, SDL provides a main function that converts URL
@@ -134,9 +140,14 @@
     #endif
 #endif /* SDL_MAIN_HANDLED */
 
-#ifndef SDLMAIN_DECLSPEC
+#ifdef SDL_MAIN_EXPORTED
+/* We need to export SDL_main so it can be launched from external code,
+   like SDLActivity.java on Android */
+#define SDLMAIN_DECLSPEC    SDL_DECLSPEC
+#else
+/* usually this is empty */
 #define SDLMAIN_DECLSPEC
-#endif
+#endif /* SDL_MAIN_EXPORTED */
 
 #ifdef SDL_WIKI_DOCUMENTATION_SECTION
 
@@ -562,14 +573,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_GDKSuspendComplete(void);
 #include <SDL3/SDL_close_code.h>
 
 #if !defined(SDL_MAIN_HANDLED) && !defined(SDL_MAIN_NOIMPL)
-    /* include header-only SDL_main implementations
-     * Note: currently Android is the only platform where we rename main() to SDL_main() but
-     *  do *not* use SDL_main_impl.h (because SDL_main() is called from external Java code).
-     *  If other platforms like that turn up, add them next to "defined(SDL_PLATFORM_ANDROID)"
-     */
-    #if (defined(SDL_MAIN_USE_CALLBACKS) || defined(SDL_MAIN_NEEDED) || defined(SDL_MAIN_AVAILABLE)) && \
-        !defined(SDL_PLATFORM_ANDROID)
-
+    /* include header-only SDL_main implementations */
+    #if defined(SDL_MAIN_USE_CALLBACKS) || defined(SDL_MAIN_NEEDED) || defined(SDL_MAIN_AVAILABLE)
         /* platforms which main (-equivalent) can be implemented in plain C */
         #include <SDL3/SDL_main_impl.h>
     #endif
diff --git a/include/SDL3/SDL_main_impl.h b/include/SDL3/SDL_main_impl.h
index 950b750bc7a82..0c19d2b3e27a5 100644
--- a/include/SDL3/SDL_main_impl.h
+++ b/include/SDL3/SDL_main_impl.h
@@ -29,7 +29,7 @@
 #endif
 
 /* if someone wants to include SDL_main.h but doesn't want the main handing magic,
-   (maybe to call SDL_RegisterApp()) they can #define SDL_MAIN_HANDLED first
+   (maybe to call SDL_RegisterApp()) they can #define SDL_MAIN_HANDLED first.
    SDL_MAIN_NOIMPL is for SDL-internal usage (only affects implementation,
    not definition of SDL_MAIN_AVAILABLE etc in SDL_main.h) and if the user wants
    to have the SDL_main implementation (from this header) in another source file
@@ -64,8 +64,9 @@
     #endif  /* SDL_MAIN_USE_CALLBACKS */
 
 
-    /* set up the usual SDL_main stuff if we're not using callbacks or if we are but need the normal entry point. */
-    #if !defined(SDL_MAIN_USE_CALLBACKS) || defined(SDL_MAIN_CALLBACK_STANDARD)
+    /* set up the usual SDL_main stuff if we're not using callbacks or if we are but need the normal entry point,
+       unless the real entry point needs to be somewhere else entirely, like Android where it's in Java code */
+    #if (!defined(SDL_MAIN_USE_CALLBACKS) || defined(SDL_MAIN_CALLBACK_STANDARD)) && !defined(SDL_MAIN_EXPORTED)
 
         #if defined(SDL_PLATFORM_WINDOWS)