SDL: Improve support for private platforms (#11220)

From 9af5ffcfbec3f46702fd2913e85e1ff44d91228a Mon Sep 17 00:00:00 2001
From: Caleb Cornett <[EMAIL REDACTED]>
Date: Tue, 15 Oct 2024 18:02:07 -0400
Subject: [PATCH] Improve support for private platforms (#11220)

---
 CMakeLists.txt                                     | 4 ++--
 include/SDL3/SDL_events.h                          | 6 ++++++
 include/SDL3/SDL_main.h                            | 6 +++++-
 include/SDL3/SDL_main_impl.h                       | 6 +++++-
 include/build_config/SDL_build_config.h            | 4 +++-
 include/build_config/SDL_build_config.h.cmake      | 2 ++
 include/build_config/SDL_build_config_android.h    | 2 ++
 include/build_config/SDL_build_config_emscripten.h | 2 ++
 include/build_config/SDL_build_config_ios.h        | 2 ++
 include/build_config/SDL_build_config_macos.h      | 2 ++
 include/build_config/SDL_build_config_windows.h    | 1 +
 include/build_config/SDL_build_config_wingdk.h     | 1 +
 src/SDL.c                                          | 4 +++-
 src/SDL_assert.c                                   | 4 +++-
 src/SDL_utils.c                                    | 4 ++--
 src/audio/SDL_audio.c                              | 3 +++
 src/audio/SDL_sysaudio.h                           | 1 +
 src/camera/SDL_syscamera.h                         | 2 --
 src/dynapi/SDL_dynapi.h                            | 4 +++-
 src/file/SDL_iostream.c                            | 4 +---
 src/joystick/SDL_gamepad_db.h                      | 3 +++
 src/joystick/SDL_joystick.c                        | 3 +++
 src/joystick/SDL_sysjoystick.h                     | 1 +
 src/thread/pthread/SDL_systhread.c                 | 8 ++++++++
 src/video/SDL_egl.c                                | 5 ++---
 src/video/SDL_sysvideo.h                           | 1 +
 src/video/SDL_video.c                              | 3 +++
 27 files changed, 70 insertions(+), 18 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index a3f521056e6cc..1aff054d818e0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -966,8 +966,8 @@ if(SDL_LIBC)
     bcopy
     calloc ceil ceilf copysign copysignf cos cosf
     _Exit exp expf
-    fabs fabsf floor floorf fmod fmodf fopen64 free fseeko fseeko64
-    getenv
+    fabs fabsf fdatasync floor floorf fmod fmodf fopen64 free fseeko fseeko64
+    getenv gethostname
     _i64toa index itoa
     log log10 log10f logf lround lroundf _ltoa
     malloc memcmp memcpy memmove memset modf modff
diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h
index 4614d30857665..bc5becb5f2299 100644
--- a/include/SDL3/SDL_events.h
+++ b/include/SDL3/SDL_events.h
@@ -229,6 +229,12 @@ typedef enum SDL_EventType
     SDL_EVENT_RENDER_TARGETS_RESET = 0x2000, /**< The render targets have been reset and their contents need to be updated */
     SDL_EVENT_RENDER_DEVICE_RESET, /**< The device has been reset and all textures need to be recreated */
 
+    /* Reserved events for private platforms */
+    SDL_EVENT_PRIVATE0 = 0x4000,
+    SDL_EVENT_PRIVATE1,
+    SDL_EVENT_PRIVATE2,
+    SDL_EVENT_PRIVATE3,
+
     /* Internal events */
     SDL_EVENT_POLL_SENTINEL = 0x7F00, /**< Signals the end of an event poll cycle */
 
diff --git a/include/SDL3/SDL_main.h b/include/SDL3/SDL_main.h
index efabb56831de5..b3455ce3d2ae5 100644
--- a/include/SDL3/SDL_main.h
+++ b/include/SDL3/SDL_main.h
@@ -49,7 +49,11 @@
 #include <SDL3/SDL_events.h>
 
 #ifndef SDL_MAIN_HANDLED
-    #ifdef SDL_PLATFORM_WIN32
+    #if defined(SDL_PLATFORM_PRIVATE_MAIN)
+        /* Private platforms may have their own ideas about entry points. */
+        #include "SDL_main_private.h"
+
+    #elif defined(SDL_PLATFORM_WIN32)
         /* On Windows SDL provides WinMain(), which parses the command line and passes
            the arguments to your main function.
 
diff --git a/include/SDL3/SDL_main_impl.h b/include/SDL3/SDL_main_impl.h
index 0c19d2b3e27a5..e5560e388aa7c 100644
--- a/include/SDL3/SDL_main_impl.h
+++ b/include/SDL3/SDL_main_impl.h
@@ -68,7 +68,11 @@
        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)
+        #if defined(SDL_PLATFORM_PRIVATE_MAIN)
+            /* Private platforms may have their own ideas about entry points. */
+            #include "SDL_main_impl_private.h"
+
+        #elif defined(SDL_PLATFORM_WINDOWS)
 
             /* these defines/typedefs are needed for the WinMain() definition */
             #ifndef WINAPI
diff --git a/include/build_config/SDL_build_config.h b/include/build_config/SDL_build_config.h
index eca4268cb3478..5fa5a4b217091 100644
--- a/include/build_config/SDL_build_config.h
+++ b/include/build_config/SDL_build_config.h
@@ -31,7 +31,9 @@
  */
 
 /* Add any platform that doesn't build using the configure system. */
-#if defined(SDL_PLATFORM_WIN32)
+#if defined(SDL_PLATFORM_PRIVATE)
+#include "SDL_build_config_private.h"
+#elif defined(SDL_PLATFORM_WIN32)
 #include "SDL_build_config_windows.h"
 #elif defined(SDL_PLATFORM_WINGDK)
 #include "SDL_build_config_wingdk.h"
diff --git a/include/build_config/SDL_build_config.h.cmake b/include/build_config/SDL_build_config.h.cmake
index a3ada8fb7e2a9..41e4c532e64fb 100644
--- a/include/build_config/SDL_build_config.h.cmake
+++ b/include/build_config/SDL_build_config.h.cmake
@@ -75,8 +75,10 @@
 #cmakedefine HAVE_MALLOC 1
 #cmakedefine HAVE_CALLOC 1
 #cmakedefine HAVE_REALLOC 1
+#cmakedefine HAVE_FDATASYNC 1
 #cmakedefine HAVE_FREE 1
 #cmakedefine HAVE_GETENV 1
+#cmakedefine HAVE_GETHOSTNAME 1
 #cmakedefine HAVE_SETENV 1
 #cmakedefine HAVE_PUTENV 1
 #cmakedefine HAVE_UNSETENV 1
diff --git a/include/build_config/SDL_build_config_android.h b/include/build_config/SDL_build_config_android.h
index db5e3cebd7299..34f26270e9012 100644
--- a/include/build_config/SDL_build_config_android.h
+++ b/include/build_config/SDL_build_config_android.h
@@ -57,8 +57,10 @@
 #define HAVE_MALLOC 1
 #define HAVE_CALLOC 1
 #define HAVE_REALLOC    1
+#define HAVE_FDATASYNC 1
 #define HAVE_FREE   1
 #define HAVE_GETENV 1
+#define HAVE_GETHOSTNAME 1
 #define HAVE_PUTENV 1
 #define HAVE_SETENV 1
 #define HAVE_UNSETENV   1
diff --git a/include/build_config/SDL_build_config_emscripten.h b/include/build_config/SDL_build_config_emscripten.h
index 32596b301f0af..9b3f853d1474a 100644
--- a/include/build_config/SDL_build_config_emscripten.h
+++ b/include/build_config/SDL_build_config_emscripten.h
@@ -60,8 +60,10 @@
 #define HAVE_MALLOC 1
 #define HAVE_CALLOC 1
 #define HAVE_REALLOC 1
+#define HAVE_FDATASYNC 1
 #define HAVE_FREE 1
 #define HAVE_GETENV 1
+#define HAVE_GETHOSTNAME 1
 #define HAVE_SETENV 1
 #define HAVE_PUTENV 1
 #define HAVE_UNSETENV 1
diff --git a/include/build_config/SDL_build_config_ios.h b/include/build_config/SDL_build_config_ios.h
index 4dc3b674d498f..b7e2843a1697f 100644
--- a/include/build_config/SDL_build_config_ios.h
+++ b/include/build_config/SDL_build_config_ios.h
@@ -49,8 +49,10 @@
 #define HAVE_MALLOC 1
 #define HAVE_CALLOC 1
 #define HAVE_REALLOC    1
+#define HAVE_FDATASYNC 1
 #define HAVE_FREE   1
 #define HAVE_GETENV 1
+#define HAVE_GETHOSTNAME 1
 #define HAVE_PUTENV 1
 #define HAVE_SETENV 1
 #define HAVE_UNSETENV   1
diff --git a/include/build_config/SDL_build_config_macos.h b/include/build_config/SDL_build_config_macos.h
index cd041b9e9eebf..c4419541dc6e9 100644
--- a/include/build_config/SDL_build_config_macos.h
+++ b/include/build_config/SDL_build_config_macos.h
@@ -54,8 +54,10 @@
 #define HAVE_MALLOC 1
 #define HAVE_CALLOC 1
 #define HAVE_REALLOC    1
+#define HAVE_FDATASYNC 1
 #define HAVE_FREE   1
 #define HAVE_GETENV 1
+#define HAVE_GETHOSTNAME 1
 #define HAVE_SETENV 1
 #define HAVE_PUTENV 1
 #define HAVE_UNSETENV   1
diff --git a/include/build_config/SDL_build_config_windows.h b/include/build_config/SDL_build_config_windows.h
index 24e21f88f60cd..b3fce6327f735 100644
--- a/include/build_config/SDL_build_config_windows.h
+++ b/include/build_config/SDL_build_config_windows.h
@@ -135,6 +135,7 @@ typedef unsigned int uintptr_t;
 #define HAVE_MALLOC 1
 #define HAVE_CALLOC 1
 #define HAVE_REALLOC 1
+#define HAVE_FDATASYNC 1
 #define HAVE_FREE 1
 #define HAVE_ABS 1
 #define HAVE_MEMSET 1
diff --git a/include/build_config/SDL_build_config_wingdk.h b/include/build_config/SDL_build_config_wingdk.h
index 5b7ebf1ddec75..a9d414044de2a 100644
--- a/include/build_config/SDL_build_config_wingdk.h
+++ b/include/build_config/SDL_build_config_wingdk.h
@@ -75,6 +75,7 @@
 #define HAVE_LIBC   1
 #define HAVE_MALLOC 1
 #define HAVE_CALLOC 1
+#define HAVE_FDATASYNC 1
 #define HAVE_REALLOC 1
 #define HAVE_FREE 1
 #define HAVE_ABS 1
diff --git a/src/SDL.c b/src/SDL.c
index 303363913bebb..aeef2ec28a38d 100644
--- a/src/SDL.c
+++ b/src/SDL.c
@@ -662,7 +662,9 @@ const char *SDL_GetRevision(void)
 // Get the name of the platform
 const char *SDL_GetPlatform(void)
 {
-#if defined(SDL_PLATFORM_AIX)
+#if defined(SDL_PLATFORM_PRIVATE)
+    return SDL_PLATFORM_PRIVATE_NAME;
+#elif defined(SDL_PLATFORM_AIX)
     return "AIX";
 #elif defined(SDL_PLATFORM_ANDROID)
     return "Android";
diff --git a/src/SDL_assert.c b/src/SDL_assert.c
index 9d022dd37eb58..e7f75962e8ccf 100644
--- a/src/SDL_assert.c
+++ b/src/SDL_assert.c
@@ -245,7 +245,9 @@ static SDL_AssertState SDLCALL SDL_PromptAssertion(const SDL_AssertData *data, v
             state = (SDL_AssertState)selected;
         }
     } else {
-#ifdef SDL_PLATFORM_EMSCRIPTEN
+#ifdef SDL_PLATFORM_PRIVATE_ASSERT
+        SDL_PRIVATE_PROMPTASSERTION();
+#elif defined(SDL_PLATFORM_EMSCRIPTEN)
         // This is nasty, but we can't block on a custom UI.
         for (;;) {
             bool okay = true;
diff --git a/src/SDL_utils.c b/src/SDL_utils.c
index b1fb89af6892f..c7f9dd6788b2c 100644
--- a/src/SDL_utils.c
+++ b/src/SDL_utils.c
@@ -20,7 +20,7 @@
 */
 #include "SDL_internal.h"
 
-#if defined(SDL_PLATFORM_UNIX) || defined(SDL_PLATFORM_APPLE)
+#ifdef HAVE_GETHOSTNAME
 #include <unistd.h>
 #endif
 
@@ -299,7 +299,7 @@ int SDL_URIToLocal(const char *src, char *dst)
             const size_t src_len = hostname_end - (src + 1);
             size_t hostname_len;
 
-#if defined(SDL_PLATFORM_UNIX) || defined(SDL_PLATFORM_APPLE)
+#ifdef HAVE_GETHOSTNAME
             char hostname[257];
             if (gethostname(hostname, 255) == 0) {
                 hostname[256] = '\0';
diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index b232bef5957e9..2de86cec5cb46 100644
--- a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -26,6 +26,9 @@
 
 // Available audio drivers
 static const AudioBootStrap *const bootstrap[] = {
+#ifdef SDL_AUDIO_DRIVER_PRIVATE
+    &PRIVATEAUDIO_bootstrap,
+#endif
 #ifdef SDL_AUDIO_DRIVER_PULSEAUDIO
 #ifdef SDL_AUDIO_DRIVER_PIPEWIRE
     &PIPEWIRE_PREFERRED_bootstrap,
diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h
index 8adfe9ab836a8..0ddc0af9278e2 100644
--- a/src/audio/SDL_sysaudio.h
+++ b/src/audio/SDL_sysaudio.h
@@ -353,6 +353,7 @@ typedef struct AudioBootStrap
 } AudioBootStrap;
 
 // Not all of these are available in a given build. Use #ifdefs, etc.
+extern AudioBootStrap PRIVATEAUDIO_bootstrap;
 extern AudioBootStrap PIPEWIRE_PREFERRED_bootstrap;
 extern AudioBootStrap PIPEWIRE_bootstrap;
 extern AudioBootStrap PULSEAUDIO_bootstrap;
diff --git a/src/camera/SDL_syscamera.h b/src/camera/SDL_syscamera.h
index 51b88355ed049..40504d30d3ded 100644
--- a/src/camera/SDL_syscamera.h
+++ b/src/camera/SDL_syscamera.h
@@ -27,8 +27,6 @@
 
 #define DEBUG_CAMERA 0
 
-typedef struct SDL_Camera SDL_Camera;
-
 /* Backends should call this as devices are added to the system (such as
    a USB camera being plugged in), and should also be called for
    for every device found during DetectDevices(). */
diff --git a/src/dynapi/SDL_dynapi.h b/src/dynapi/SDL_dynapi.h
index be52f2c298753..fd2e3b06abd99 100644
--- a/src/dynapi/SDL_dynapi.h
+++ b/src/dynapi/SDL_dynapi.h
@@ -43,7 +43,9 @@
 #include "TargetConditionals.h"
 #endif
 
-#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE // probably not useful on iOS.
+#if defined(SDL_PLATFORM_PRIVATE) // probably not useful on private platforms.
+#define SDL_DYNAMIC_API 0
+#elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE // probably not useful on iOS.
 #define SDL_DYNAMIC_API 0
 #elif defined(SDL_PLATFORM_ANDROID) // probably not useful on Android.
 #define SDL_DYNAMIC_API 0
diff --git a/src/file/SDL_iostream.c b/src/file/SDL_iostream.c
index 1b51cd0992a3e..8fde6dcf9ec81 100644
--- a/src/file/SDL_iostream.c
+++ b/src/file/SDL_iostream.c
@@ -370,10 +370,8 @@ static int SDL_fdatasync(int fd)
     result = fcntl(fd, F_FULLFSYNC);
 #elif defined(SDL_PLATFORM_HAIKU)
     result = fsync(fd);
-#elif defined(_POSIX_SYNCHRONIZED_IO)  // POSIX defines this if fdatasync() exists, so we don't need a CMake test.
-#ifndef SDL_PLATFORM_RISCOS  // !!! FIXME: however, RISCOS doesn't have the symbol...maybe we need to link to an extra library or something?
+#elif defined(HAVE_FDATASYNC)
     result = fdatasync(fd);
-#endif
 #endif
     return result;
 }
diff --git a/src/joystick/SDL_gamepad_db.h b/src/joystick/SDL_gamepad_db.h
index 60914af3b61ed..64be375c1445d 100644
--- a/src/joystick/SDL_gamepad_db.h
+++ b/src/joystick/SDL_gamepad_db.h
@@ -29,6 +29,9 @@
    Alternatively, you can use the app located in test/controllermap
  */
 static const char *s_GamepadMappings[] = {
+#ifdef SDL_JOYSTICK_PRIVATE
+    SDL_PRIVATE_GAMEPAD_DEFINITIONS
+#endif
 #ifdef SDL_JOYSTICK_XINPUT
     "xinput,*,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
 #endif
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index e8cd6fd9e665e..43d51fe2dd5af 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -52,6 +52,9 @@ static SDL_JoystickDriver *SDL_joystick_drivers[] = {
 #ifdef SDL_JOYSTICK_HIDAPI // Highest priority driver for supported devices
     &SDL_HIDAPI_JoystickDriver,
 #endif
+#ifdef SDL_JOYSTICK_PRIVATE
+    &SDL_PRIVATE_JoystickDriver,
+#endif
 #ifdef SDL_JOYSTICK_GAMEINPUT // Higher priority than other Windows drivers
     &SDL_GAMEINPUT_JoystickDriver,
 #endif
diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h
index 30934fb4a79d5..49e784d019f87 100644
--- a/src/joystick/SDL_sysjoystick.h
+++ b/src/joystick/SDL_sysjoystick.h
@@ -240,6 +240,7 @@ typedef struct SDL_JoystickDriver
 #define SDL_LED_MIN_REPEAT_MS 5000
 
 // The available joystick drivers
+extern SDL_JoystickDriver SDL_PRIVATE_JoystickDriver;
 extern SDL_JoystickDriver SDL_ANDROID_JoystickDriver;
 extern SDL_JoystickDriver SDL_BSD_JoystickDriver;
 extern SDL_JoystickDriver SDL_DARWIN_JoystickDriver;
diff --git a/src/thread/pthread/SDL_systhread.c b/src/thread/pthread/SDL_systhread.c
index feaae3b9657d2..9ece731222661 100644
--- a/src/thread/pthread/SDL_systhread.c
+++ b/src/thread/pthread/SDL_systhread.c
@@ -26,7 +26,9 @@
 #include <pthread_np.h>
 #endif
 
+#ifdef HAVE_SIGNAL_H
 #include <signal.h>
+#endif
 #include <errno.h>
 
 #ifdef SDL_PLATFORM_LINUX
@@ -55,11 +57,13 @@
 #include <kernel/OS.h>
 #endif
 
+#ifdef HAVE_SIGNAL_H
 // List of signals to mask in the subthreads
 static const int sig_list[] = {
     SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGWINCH,
     SIGVTALRM, SIGPROF, 0
 };
+#endif
 
 static void *RunThread(void *data)
 {
@@ -117,8 +121,10 @@ bool SDL_SYS_CreateThread(SDL_Thread *thread,
 
 void SDL_SYS_SetupThread(const char *name)
 {
+#ifdef HAVE_SIGNAL_H
     int i;
     sigset_t mask;
+#endif
 
     if (name) {
 #if (defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_LINUX)) && defined(HAVE_DLOPEN)
@@ -154,12 +160,14 @@ void SDL_SYS_SetupThread(const char *name)
 #endif
     }
 
+#ifdef HAVE_SIGNAL_H
     // Mask asynchronous signals for this thread
     sigemptyset(&mask);
     for (i = 0; sig_list[i]; ++i) {
         sigaddset(&mask, sig_list[i]);
     }
     pthread_sigmask(SIG_BLOCK, &mask, 0);
+#endif
 
 #ifdef PTHREAD_CANCEL_ASYNCHRONOUS
     // Allow ourselves to be asynchronously cancelled
diff --git a/src/video/SDL_egl.c b/src/video/SDL_egl.c
index 4caf2db5b3b44..703984d00894d 100644
--- a/src/video/SDL_egl.c
+++ b/src/video/SDL_egl.c
@@ -300,7 +300,9 @@ void SDL_EGL_UnloadLibrary(SDL_VideoDevice *_this)
 static bool SDL_EGL_LoadLibraryInternal(SDL_VideoDevice *_this, const char *egl_path)
 {
     SDL_SharedObject *egl_dll_handle = NULL;
+#if !defined(SDL_VIDEO_STATIC_ANGLE) && !defined(SDL_VIDEO_DRIVER_VITA)
     SDL_SharedObject *opengl_dll_handle = NULL;
+#endif
     const char *path = NULL;
 #if defined(SDL_VIDEO_DRIVER_WINDOWS)
     const char *d3dcompiler;
@@ -426,9 +428,6 @@ static bool SDL_EGL_LoadLibraryInternal(SDL_VideoDevice *_this, const char *egl_
 #endif
 
     _this->egl_data->egl_dll_handle = egl_dll_handle;
-#ifdef SDL_VIDEO_DRIVER_VITA
-    _this->egl_data->opengl_dll_handle = opengl_dll_handle;
-#endif
 
     // Load new function pointers
     LOAD_FUNC(PFNEGLGETDISPLAYPROC, eglGetDisplay);
diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index db53fe6e00aff..bd8c56982751d 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -498,6 +498,7 @@ typedef struct VideoBootStrap
 } VideoBootStrap;
 
 // Not all of these are available in a given build. Use #ifdefs, etc.
+extern VideoBootStrap PRIVATE_bootstrap;
 extern VideoBootStrap COCOA_bootstrap;
 extern VideoBootStrap X11_bootstrap;
 extern VideoBootStrap WINDOWS_bootstrap;
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 4b58b65235ff9..c0687fb4cfc97 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -71,6 +71,9 @@
 
 // Available video drivers
 static VideoBootStrap *bootstrap[] = {
+#ifdef SDL_VIDEO_DRIVER_PRIVATE
+    &PRIVATE_bootstrap,
+#endif
 #ifdef SDL_VIDEO_DRIVER_COCOA
     &COCOA_bootstrap,
 #endif