SDL_net: stub: Add a stub library option.

From f8a578178560452aaafa18eb875903b1b8ee45cf Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Sat, 9 May 2026 23:31:18 -0400
Subject: [PATCH] stub: Add a stub library option.

Now you can link against a library that has all of SDL_net's functions, but
all those functions will fail.

This is useful to build something for a platform that doesn't have real
network sockets at the moment, like MS-DOS or Emscripten, without having to
sprinkle `#ifdef` all over your code.

Fixes #160.
---
 CMakeLists.txt          | 14 +++++++++-
 src/SDL_net_stub_only.c | 58 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 71 insertions(+), 1 deletion(-)
 create mode 100644 src/SDL_net_stub_only.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 07c96f16..ec0c8fa6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -104,7 +104,19 @@ endif()
 set(PC_LIBS)
 set(PC_REQUIRES)
 
-add_library(${sdl3_net_target_name} src/SDL_net.c)
+set(PLATFORM_UNSUPPORTED False)
+if (DOS OR EMSCRIPTEN)  # These either don't have networking at all, or have needs we don't currently meet.
+    set(PLATFORM_UNSUPPORTED True)
+endif()
+
+option(SDLNET_STUB_ONLY "Build a stub library that does nothing" ${PLATFORM_UNSUPPORTED})
+if(SDLNET_STUB_ONLY)
+    message(WARNING "Only building a stub library. The functions will be there but all of them will fail!")
+    add_library(${sdl3_net_target_name} src/SDL_net_stub_only.c)
+else()
+    add_library(${sdl3_net_target_name} src/SDL_net.c)
+endif()
+
 add_library(SDL3_net::${sdl3_net_target_name} ALIAS ${sdl3_net_target_name})
 if("c_std_99" IN_LIST CMAKE_C_COMPILE_FEATURES)
     target_compile_features(${sdl3_net_target_name} PRIVATE c_std_99)
diff --git a/src/SDL_net_stub_only.c b/src/SDL_net_stub_only.c
new file mode 100644
index 00000000..04294f4d
--- /dev/null
+++ b/src/SDL_net_stub_only.c
@@ -0,0 +1,58 @@
+/*
+  SDL_net: A simple networking library for use with SDL
+  Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "SDL3_net/SDL_net.h"
+
+// don't do anything. Sorry!
+int NET_Version(void) { return SDL_NET_VERSION; }
+bool NET_Init(void) { return true; }
+void NET_Quit(void) {}
+NET_Address * NET_ResolveHostname(const char *host) { SDL_Unsupported(); return NULL; }
+NET_Status NET_WaitUntilResolved(NET_Address *address, Sint32 timeout) { SDL_Unsupported(); return NET_FAILURE; }
+NET_Status NET_GetAddressStatus(NET_Address *address) { SDL_Unsupported(); return NET_FAILURE; }
+const char * NET_GetAddressString(NET_Address *address) { SDL_Unsupported(); return NULL; }
+NET_Address *NET_RefAddress(NET_Address *address) { SDL_Unsupported(); return NULL; }
+void NET_UnrefAddress(NET_Address *address) {}
+void NET_SimulateAddressResolutionLoss(int percent_loss) {}
+int NET_CompareAddresses(const NET_Address *a, const NET_Address *b) { return 0; }
+NET_Address **NET_GetLocalAddresses(int *num_addresses) { SDL_Unsupported(); return NULL; }
+void NET_FreeLocalAddresses(NET_Address **addresses) {}
+NET_StreamSocket * NET_CreateClient(NET_Address *address, Uint16 port) { SDL_Unsupported(); return NULL; }
+NET_Status NET_WaitUntilConnected(NET_StreamSocket *sock, Sint32 timeout) { SDL_Unsupported(); return NET_FAILURE; }
+NET_Server * NET_CreateServer(NET_Address *addr, Uint16 port) { SDL_Unsupported(); return NULL; }
+bool NET_AcceptClient(NET_Server *server, NET_StreamSocket **client_stream) { SDL_Unsupported(); return false; }
+void NET_DestroyServer(NET_Server *server) {}
+NET_Address * NET_GetStreamSocketAddress(NET_StreamSocket *sock) { SDL_Unsupported(); return NULL; }
+NET_Status NET_GetConnectionStatus(NET_StreamSocket *sock) { SDL_Unsupported(); return NET_FAILURE; }
+bool NET_WriteToStreamSocket(NET_StreamSocket *sock, const void *buf, int buflen) { SDL_Unsupported(); return false; }
+int NET_GetStreamSocketPendingWrites(NET_StreamSocket *sock) { SDL_Unsupported(); return -1; }
+int NET_WaitUntilStreamSocketDrained(NET_StreamSocket *sock, Sint32 timeout) { SDL_Unsupported(); return -1; }
+int NET_ReadFromStreamSocket(NET_StreamSocket *sock, void *buf, int buflen) { SDL_Unsupported(); return -1; }
+void NET_SimulateStreamPacketLoss(NET_StreamSocket *sock, int percent_loss) {}
+void NET_DestroyStreamSocket(NET_StreamSocket *sock) {}
+NET_DatagramSocket * NET_CreateDatagramSocket(NET_Address *addr, Uint16 port) { SDL_Unsupported(); return NULL; }
+bool NET_SendDatagram(NET_DatagramSocket *sock, NET_Address *address, Uint16 port, const void *buf, int buflen) { SDL_Unsupported(); return false; }
+bool NET_ReceiveDatagram(NET_DatagramSocket *sock, NET_Datagram **dgram) { SDL_Unsupported(); return false; }
+void NET_DestroyDatagram(NET_Datagram *dgram) {}
+void NET_SimulateDatagramPacketLoss(NET_DatagramSocket *sock, int percent_loss) {}
+void NET_DestroyDatagramSocket(NET_DatagramSocket *sock) {}
+int NET_WaitUntilInputAvailable(void **vsockets, int numsockets, Sint32 timeout) { SDL_Unsupported(); return -1; }
+