SDL: cmake: check whether libunwind can be compiled and linked against

From 0262f757e191c478e49e15b963921696f532d8e3 Mon Sep 17 00:00:00 2001
From: Anonymous Maarten <[EMAIL REDACTED]>
Date: Tue, 4 Jul 2023 23:22:38 +0200
Subject: [PATCH] cmake: check whether libunwind can be compiled and linked
 against

---
 CMakeLists.txt        | 18 +++--------------
 cmake/sdlchecks.cmake | 47 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+), 15 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 742310e18ebf..3e6752c74279 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1023,9 +1023,6 @@ if(SDL_LIBC)
         sys/types.h
         wchar.h
     )
-    if(NOT EMSCRIPTEN)
-      list(APPEND headers_to_check libunwind.h)
-    endif()
     foreach(_HEADER ${headers_to_check})
       string(TOUPPER "HAVE_${_HEADER}" _UPPER)
       string(REGEX REPLACE "[./]" "_" _HAVE_H ${_UPPER})
@@ -1405,10 +1402,7 @@ elseif(EMSCRIPTEN)
   endif()
 
   CheckPTHREAD()
-
-  if(HAVE_LIBUNWIND_H)
-    list(APPEND EXTRA_TEST_LIBS unwind)
-  endif()
+  CheckLibUnwind()
 
 elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
   if(SDL_AUDIO)
@@ -1572,15 +1566,8 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
         endif()
       endif()
 
-      if(HAVE_LIBUNWIND_H)
-        # We've already found the header, so link the lib if present.
-        # NB: This .pc file is not present on FreeBSD where the implicitly
-        # linked base system libgcc_s includes all libunwind ABI.
-        pkg_search_module(UNWIND libunwind)
-        pkg_search_module(UNWIND_GENERIC libunwind-generic)
-        list(APPEND EXTRA_TEST_LIBS ${UNWIND_LIBRARIES} ${UNWIND_GENERIC_LIBRARIES})
-      endif()
     endif()
+    CheckLibUnwind()
 
     if(HAVE_DBUS_DBUS_H)
       list(APPEND SOURCE_FILES "${SDL2_SOURCE_DIR}/src/core/linux/SDL_dbus.c")
@@ -3453,6 +3440,7 @@ if(SDL_TEST)
       "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
       "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/SDL2>")
   target_link_libraries(SDL2_test PRIVATE ${EXTRA_TEST_LIBS})
+  target_include_directories(SDL2_test PRIVATE ${EXTRA_TEST_INCLUDES})
   set_property(TARGET SDL2_test APPEND PROPERTY COMPATIBLE_INTERFACE_STRING "SDL_VERSION")
   set_property(TARGET SDL2_test PROPERTY INTERFACE_SDL_VERSION "SDL2")
 endif()
diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake
index c4aec174e35e..7b5c882b32f5 100644
--- a/cmake/sdlchecks.cmake
+++ b/cmake/sdlchecks.cmake
@@ -1336,3 +1336,50 @@ macro(CheckLibUDev)
     endif()
   endif()
 endmacro()
+
+
+macro(CheckLibUnwind)
+  set(found_libunwind FALSE)
+  set(_libunwind_src "#include <libunwind.h>\nint main() {unw_context_t context; unw_getcontext(&context); return 0;}")
+
+  if(NOT found_libunwind)
+    cmake_push_check_state()
+    check_c_source_compiles("${_libunwind_src}" LIBC_HAS_WORKING_LIBUNWIND)
+    cmake_pop_check_state()
+    if(LIBC_HAS_WORKING_LIBUNWIND)
+      set(found_libunwind TRUE)
+    endif()
+  endif()
+
+  if(NOT found_libunwind)
+    cmake_push_check_state()
+    list(APPEND CMAKE_REQUIRED_LIBRARIES "unwind")
+    check_c_source_compiles("${_libunwind_src}" LIBUNWIND_HAS_WORKINGLIBUNWIND)
+    cmake_pop_check_state()
+    if(LIBUNWIND_HAS_WORKINGLIBUNWIND)
+      set(found_libunwind TRUE)
+      list(APPEND EXTRA_TEST_LIBS unwind)
+    endif()
+  endif()
+
+  if(NOT found_libunwind)
+    set(LibUnwind_PKG_CONFIG_SPEC libunwind libunwind-generic)
+    pkg_check_modules(PC_LIBUNWIND IMPORTED_TARGET ${LibUnwind_PKG_CONFIG_SPEC})
+    if(PC_LIBUNWIND_FOUND)
+      cmake_push_check_state()
+      list(APPEND CMAKE_REQUIRED_LIBRARIES ${PC_LIBUNWIND_LIBRARIES})
+      list(APPEND CMAKE_REQUIRED_INCLUDES ${PC_LIBUNWIND_INCLUDE_DIRS})
+      check_c_source_compiles("${_libunwind_src}" PC_LIBUNWIND_HAS_WORKING_LIBUNWIND)
+      cmake_pop_check_state()
+      if(PC_LIBUNWIND_HAS_WORKING_LIBUNWIND)
+        set(found_libunwind TRUE)
+        list(APPEND EXTRA_TEST_LIBS ${PC_LIBUNWIND_LIBRARIES})
+        list(APPEND EXTRA_TEST_INCLUDES ${PC_LIBUNWIND_INCLUDE_DIRS})
+      endif()
+    endif()
+  endif()
+
+  if(found_libunwind)
+    set(HAVE_LIBUNWIND_H TRUE)
+  endif()
+endmacro()