SDL: Add support for tcc to cmake (#14464)

From d4bef0d5ba7d231bd757f4b59e966c4b5b086553 Mon Sep 17 00:00:00 2001
From: tsst-tsst <[EMAIL REDACTED]>
Date: Sat, 15 Nov 2025 20:24:15 +0100
Subject: [PATCH] Add support for tcc to cmake (#14464)

This PR adds support to the cmake build scripts so to allow building SDL with the Tiny C Compiler (tcc).

TinyCC supports the subset of C99 used by SDL and will complete the build once the --version-script linker flag is removed. The changes have been tested with various build configurations, including X11 and Wayland, and using tcc version 0.9.28rc 2025-10-27 mob@f4e01bfc on x86_64 Linux.
---
 CMakeLists.txt            | 18 +++++++++++++-----
 cmake/sdlcompilers.cmake  |  9 ++++++++-
 include/SDL3/SDL_assert.h |  2 +-
 src/atomic/SDL_spinlock.c |  2 +-
 4 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8bfe65da1f92d..16111a817dc6c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -169,12 +169,12 @@ else()
 endif()
 
 set(SDL_ASSEMBLY_DEFAULT OFF)
-if(USE_CLANG OR USE_GCC OR USE_INTELCC OR MSVC_VERSION GREATER 1400)
+if(USE_CLANG OR USE_GCC OR USE_INTELCC OR USE_TCC OR MSVC_VERSION GREATER 1400)
   set(SDL_ASSEMBLY_DEFAULT ON)
 endif()
 
 set(SDL_GCC_ATOMICS_DEFAULT OFF)
-if(USE_GCC OR USE_CLANG OR USE_INTELCC OR USE_QCC)
+if(USE_GCC OR USE_CLANG OR USE_INTELCC OR USE_QCC OR TCC)
   set(SDL_GCC_ATOMICS_DEFAULT ON)
 endif()
 
@@ -463,7 +463,10 @@ if(SDL_SHARED)
   if ("c_std_99" IN_LIST CMAKE_C_COMPILE_FEATURES)
     target_compile_features(SDL3-shared PRIVATE c_std_99)
   else()
-    message(WARNING "target_compile_features does not know c_std_99 for C compiler")
+    # tcc does support the subset of C99 used by SDL
+    if (NOT USE_TCC)
+      message(WARNING "target_compile_features does not know c_std_99 for C compiler")
+    endif()
   endif()
 endif()
 
@@ -476,7 +479,9 @@ if(SDL_STATIC)
   if ("c_std_99" IN_LIST CMAKE_C_COMPILE_FEATURES)
     target_compile_features(SDL3-static PRIVATE c_std_99)
   else()
-    message(WARNING "target_compile_features does not know c_std_99 for C compiler")
+    if (NOT USE_TCC)
+      message(WARNING "target_compile_features does not know c_std_99 for C compiler")
+    endif()
   endif()
 endif()
 
@@ -510,7 +515,10 @@ check_linker_supports_version_file(HAVE_WL_VERSION_SCRIPT)
 if(HAVE_WL_VERSION_SCRIPT)
   sdl_shared_link_options("-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/dynapi/SDL_dynapi.sym")
 else()
-  if((LINUX AND LIBC_IS_GLIBC) OR ANDROID)
+   # When building with tcc on Linux+glibc or Android, avoid emitting an error
+   # for lack of support of the version-script linker flag: the option will be
+   # silently ignored by the compiler and the build will still succeed.
+   if(((LINUX AND LIBC_IS_GLIBC) OR ANDROID) AND (NOT USE_TCC))
     message(FATAL_ERROR "Linker does not support '-Wl,--version-script=xxx.sym'. This is required on the current host platform (${SDL_CMAKE_PLATFORM}).")
   endif()
 endif()
diff --git a/cmake/sdlcompilers.cmake b/cmake/sdlcompilers.cmake
index af80a8eb2449b..ab62c5012ebfc 100644
--- a/cmake/sdlcompilers.cmake
+++ b/cmake/sdlcompilers.cmake
@@ -3,6 +3,7 @@ macro(SDL_DetectCompiler)
   set(USE_GCC FALSE)
   set(USE_INTELCC FALSE)
   set(USE_QCC FALSE)
+  set(USE_TCC FALSE)
   if(CMAKE_C_COMPILER_ID MATCHES "Clang|IntelLLVM")
     set(USE_CLANG TRUE)
     # Visual Studio 2019 v16.2 added support for Clang/LLVM.
@@ -16,6 +17,8 @@ macro(SDL_DetectCompiler)
     set(USE_INTELCC TRUE)
   elseif(CMAKE_C_COMPILER_ID MATCHES "QCC")
     set(USE_QCC TRUE)
+  elseif(CMAKE_C_COMPILER_ID MATCHES "TinyCC")
+    set(USE_TCC TRUE)
   endif()
 endmacro()
 
@@ -39,7 +42,7 @@ function(SDL_AddCommonCompilerFlags TARGET)
     cmake_pop_check_state()
   endif()
 
-  if(USE_GCC OR USE_CLANG OR USE_INTELCC OR USE_QCC)
+  if(USE_GCC OR USE_CLANG OR USE_INTELCC OR USE_QCC OR USE_TCC)
     if(MINGW)
       # See if GCC's -gdwarf-4 is supported
       # See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101377 for why this is needed on Windows
@@ -159,6 +162,10 @@ function(SDL_AddCommonCompilerFlags TARGET)
       sdl_target_compile_option_all_languages(${TARGET} "-fdiagnostics-color=always")
     endif()
   endif()
+
+  if(USE_TCC)
+      sdl_target_compile_option_all_languages(${TARGET} "-DSTBI_NO_SIMD")
+  endif()
 endfunction()
 
 function(check_x86_source_compiles BODY VAR)
diff --git a/include/SDL3/SDL_assert.h b/include/SDL3/SDL_assert.h
index ddb89b8848f85..f0c4637b93c12 100644
--- a/include/SDL3/SDL_assert.h
+++ b/include/SDL3/SDL_assert.h
@@ -136,7 +136,7 @@ extern "C" {
     #define SDL_TriggerBreakpoint() __builtin_debugtrap()
 #elif SDL_HAS_BUILTIN(__builtin_trap)
     #define SDL_TriggerBreakpoint() __builtin_trap()
-#elif (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
+#elif (defined(__GNUC__) || defined(__clang__) || defined(__TINYC__)) && (defined(__i386__) || defined(__x86_64__))
     #define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "int $3\n\t" )
 #elif (defined(__GNUC__) || defined(__clang__)) && defined(__riscv)
     #define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "ebreak\n\t" )
diff --git a/src/atomic/SDL_spinlock.c b/src/atomic/SDL_spinlock.c
index 75bacda7c992a..2f609327e2137 100644
--- a/src/atomic/SDL_spinlock.c
+++ b/src/atomic/SDL_spinlock.c
@@ -91,7 +91,7 @@ bool SDL_TryLockSpinlock(SDL_SpinLock *lock)
         : "cc", "memory");
     return result == 0;
 
-#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+#elif (defined(__GNUC__) || defined(__TINYC__)) && (defined(__i386__) || defined(__x86_64__))
     int result;
     __asm__ __volatile__(
         "lock ; xchgl %0, (%1)\n"