SDL: cmake: fall back to per-cpu test when all-in-one test fails

From 4b0f52b04e0038e72026d842bd2310f278cc2499 Mon Sep 17 00:00:00 2001
From: Anonymous Maarten <[EMAIL REDACTED]>
Date: Thu, 30 May 2024 20:45:14 +0200
Subject: [PATCH] cmake: fall back to per-cpu test when all-in-one test fails

The 'all-in-one' test fails for Emscripten because try_compile does not copy back the actual binary:
the wasm file contains the machine parseable strings, not the html or js file(s).
---
 cmake/sdlcpu.cmake | 198 ++++++++++++++++++++++-----------------------
 1 file changed, 97 insertions(+), 101 deletions(-)

diff --git a/cmake/sdlcpu.cmake b/cmake/sdlcpu.cmake
index fbaa0f389de53..3c22b2782c087 100644
--- a/cmake/sdlcpu.cmake
+++ b/cmake/sdlcpu.cmake
@@ -1,10 +1,10 @@
 function(SDL_DetectTargetCPUArchitectures DETECTED_ARCHS)
 
-  set(DETECTABLE_ARCHS ARM32 ARM64 EMSCRIPTEN LOONGARCH64 POWERPC32 POWERPC64 X86 X64)
+  set(known_archs EMSCRIPTEN ARM32 ARM64 LOONGARCH64 POWERPC32 POWERPC64 X86 X64)
 
   if(APPLE AND CMAKE_OSX_ARCHITECTURES)
-    foreach(arch IN LISTS DETECTABLE_ARCHS)
-      set(SDL_CPU_${arch} "0")
+    foreach(known_arch IN LISTS known_archs)
+      set(SDL_CPU_${known_arch} "0")
     endforeach()
     set(detected_archs)
     foreach(osx_arch IN LISTS CMAKE_OSX_ARCHITECTURES)
@@ -21,9 +21,9 @@ function(SDL_DetectTargetCPUArchitectures DETECTED_ARCHS)
   endif()
 
   set(detected_archs)
-  foreach(arch IN LISTS DETECTABLE_ARCHS)
-    if(SDL_CPU_${arch})
-      list(APPEND detected_archs "${arch}")
+  foreach(known_arch IN LISTS known_archs)
+    if(SDL_CPU_${known_arch})
+      list(APPEND detected_archs "${known_arch}")
     endif()
   endforeach()
 
@@ -32,118 +32,114 @@ function(SDL_DetectTargetCPUArchitectures DETECTED_ARCHS)
     return()
   endif()
 
-  set(src_arch_detect [=====[
-
-#if defined(__arm__) || defined(_M_ARM)
-#define ARCH_ARM32 "1"
-#else
-#define ARCH_ARM32 "0"
-#endif
-const char *arch_arm32 = "INFO<ARM32=" ARCH_ARM32 ">";
-
-#if defined(__aarch64__) || defined(_M_ARM64)
-#define ARCH_ARM64 "1"
-#else
-#define ARCH_ARM64 "0"
-#endif
-const char *arch_arm64 = "INFO<ARM64=" ARCH_ARM64 ">";
-
-#if defined(__EMSCRIPTEN__)
-#define ARCH_EMSCRIPTEN "1"
-#else
-#define ARCH_EMSCRIPTEN "0"
-#endif
-const char *arch_emscripten = "INFO<EMSCRIPTEN=" ARCH_EMSCRIPTEN ">";
-
-#if defined(__loongarch64)
-#define ARCH_LOONGARCH64 "1"
+  set(arch_check_ARM32 "defined(__arm__) || defined(_M_ARM)")
+  set(arch_check_ARM64 "defined(__aarch64__) || defined(_M_ARM64)")
+  set(arch_check_EMSCRIPTEN "defined(__EMSCRIPTEN__)")
+  set(arch_check_LOONGARCH64 "defined(__loongarch64)")
+  set(arch_check_POWERPC32 "(defined(__PPC__) || defined(__powerpc__)) && !defined(__powerpc64__)")
+  set(arch_check_POWERPC64 "defined(__PPC64__) || defined(__powerpc64__)")
+  set(arch_check_X86 "defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) ||defined( __i386) || defined(_M_IX86)")
+  set(arch_check_X64 "defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)")
+
+  set(src_vars "")
+  set(src_main "")
+  foreach(known_arch IN LISTS known_archs)
+    set(detected_${known_arch} "0")
+
+    string(APPEND src_vars "
+#if ${arch_check_${known_arch}}
+#define ARCH_${known_arch} \"1\"
 #else
-#define ARCH_LOONGARCH64 "0"
+#define ARCH_${known_arch} \"0\"
 #endif
-const char *arch_loongarch64 = "INFO<LOONGARCH64=" ARCH_LOONGARCH64 ">";
-
-#if (defined(__PPC__) || defined(__powerpc__)) && !defined(__powerpc64__)
-#define ARCH_POWERPC32 "1"
-#else
-#define ARCH_POWERPC32 "0"
-#endif
-const char *arch_powerpc32 = "INFO<ARCH_POWERPC32=" ARCH_POWERPC32 ">";
-
-#if defined(__PPC64__) || defined(__powerpc64__)
-#define ARCH_POWERPC64 "1"
-#else
-#define ARCH_POWERPC64 "0"
-#endif
-const char *arch_powerpc64 = "INFO<POWERPC64=" ARCH_POWERPC64 ">";
-
-#if defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) ||defined( __i386) || defined(_M_IX86)
-#define ARCH_X86 "1"
-#else
-#define ARCH_X86 "0"
-#endif
-const char *arch_x86 = "INFO<X86=" ARCH_X86 ">";
-
-#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
-#define ARCH_X64 "1"
-#else
-#define ARCH_X64 "0"
-#endif
-const char *arch_x64 = "INFO<X64=" ARCH_X64 ">";
+const char *arch_${known_arch} = \"INFO<${known_arch}=\" ARCH_${known_arch} \">\";
+")
+    string(APPEND src_main "
+  result += arch_${known_arch}[argc];")
+  endforeach()
 
+  set(src_arch_detect "${src_vars}
 int main(int argc, char *argv[]) {
-  (void) argv;
-  int result = argc;
-  result += arch_arm32[argc];
-  result += arch_arm64[argc];
-  result += arch_emscripten[argc];
-  result += arch_loongarch64[argc];
-  result += arch_powerpc32[argc];
-  result += arch_powerpc64[argc];
-  result += arch_x86[argc];
-  result += arch_x64[argc];
+  (void)argv;
+  int result = 0;
+${src_main}
   return result;
-}
-]=====])
+}")
 
   set(path_src_arch_detect "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeTmp/SDL_detect_arch.c")
   file(WRITE "${path_src_arch_detect}" "${src_arch_detect}")
   set(path_dir_arch_detect "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeTmp/SDL_detect_arch")
   set(path_bin_arch_detect "${path_dir_arch_detect}/bin")
 
+  set(detected_archs)
+
   set(msg "Detecting Target CPU Architecture")
   message(STATUS "${msg}")
 
-  try_compile(COMPILED_RES
-          "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeTmp/SDL_detect_arch"
-          SOURCES "${path_src_arch_detect}"
-          COPY_FILE "${path_bin_arch_detect}"
-          )
-  if(NOT COMPILED_RES)
+  include(CMakePushCheckState)
+
+  cmake_push_check_state(RESET)
+  try_compile(SDL_CPU_CHECK_ALL
+    "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeTmp/SDL_detect_arch"
+    SOURCES "${path_src_arch_detect}"
+    COPY_FILE "${path_bin_arch_detect}"
+  )
+  cmake_pop_check_state()
+  if(NOT SDL_CPU_CHECK_ALL)
     message(STATUS "${msg} - <ERROR>")
     message(WARNING "Failed to compile source detecting the target CPU architecture")
-  endif()
-
-  set(re "INFO<([A-Z0-9]+)=([01])>")
-  file(STRINGS "${path_bin_arch_detect}" infos REGEX "${re}")
-
-  set(detected_archs)
-
-  foreach(info_arch_01 IN LISTS infos)
-    string(REGEX MATCH "${re}" A "${info_arch_01}")
-    if(NOT "${CMAKE_MATCH_1}" IN_LIST DETECTABLE_ARCHS)
-      message(WARNING "Unknown architecture: \"${CMAKE_MATCH_1}\"")
-      continue()
-    endif()
-    set(arch "${CMAKE_MATCH_1}")
-    set(arch_01 "${CMAKE_MATCH_2}")
-    if(arch_01)
-      list(APPEND detected_archs "${arch}")
-    endif()
-    set("SDL_CPU_${arch}" "${arch_01}" CACHE BOOL "Detected architecture ${arch}")
-  endforeach()
+  else()
+    set(re "INFO<([A-Z0-9]+)=([01])>")
+    file(STRINGS "${path_bin_arch_detect}" infos REGEX "${re}")
+
+    foreach(info_arch_01 IN LISTS infos)
+      string(REGEX MATCH "${re}" A "${info_arch_01}")
+      if(NOT "${CMAKE_MATCH_1}" IN_LIST known_archs)
+        message(WARNING "Unknown architecture: \"${CMAKE_MATCH_1}\"")
+        continue()
+      endif()
+      set(arch "${CMAKE_MATCH_1}")
+      set(arch_01 "${CMAKE_MATCH_2}")
+      set(detected_${arch} "${arch_01}")
+    endforeach()
 
-  message(STATUS "${msg} - ${detected_archs}")
+    foreach(known_arch IN LISTS known_archs)
+      if(detected_${known_arch})
+        list(APPEND detected_archs ${known_arch})
+      endif()
+    endforeach()
+  endif()
 
+  if(detected_archs)
+    foreach(known_arch IN LISTS known_archs)
+      set("SDL_CPU_${known_arch}" "${detected_${known_arch}}" CACHE BOOL "Detected architecture ${known_arch}")
+    endforeach()
+    message(STATUS "${msg} - ${detected_archs}")
+  else()
+    include(CheckCSourceCompiles)
+    cmake_push_check_state(RESET)
+    foreach(known_arch IN LISTS known_archs)
+      if(NOT detected_archs)
+        set(cache_variable "SDL_CPU_${known_arch}")
+          set(test_src "
+        int main(int argc, char *argv[]) {
+        #if ${arch_check_${known_arch}}
+          return 0;
+        #else
+          choke
+        #endif
+        }
+        ")
+        check_c_source_compiles("${test_src}" "${cache_variable}")
+        if(${cache_variable})
+          set(SDL_CPU_${known_arch} "1" CACHE BOOL "Detected architecture ${known_arch}")
+          set(detected_archs ${known_arch})
+        else()
+          set(SDL_CPU_${known_arch} "0" CACHE BOOL "Detected architecture ${known_arch}")
+        endif()
+      endif()
+    endforeach()
+    cmake_pop_check_state()
+  endif()
   set("${DETECTED_ARCHS}" "${detected_archs}" PARENT_SCOPE)
-
 endfunction()