SDL: cmake: make SDL2Config.cmake compatible with autotools' sdl2-config.cmake

From 5ec2d46f476f5019d1d0bb8345b7f6f79222d0c1 Mon Sep 17 00:00:00 2001
From: Anonymous Maarten <[EMAIL REDACTED]>
Date: Fri, 3 Jun 2022 20:12:52 +0200
Subject: [PATCH] cmake: make SDL2Config.cmake compatible with autotools'
 sdl2-config.cmake

---
 CMakeLists.txt      |  50 ++++++++++++------
 SDL2Config.cmake    | 122 --------------------------------------------
 SDL2Config.cmake.in |  60 ++++++++++++++++++++++
 3 files changed, 93 insertions(+), 139 deletions(-)
 delete mode 100644 SDL2Config.cmake
 create mode 100644 SDL2Config.cmake.in

diff --git a/CMakeLists.txt b/CMakeLists.txt
index a1bb36477ba..e434a8acd99 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -287,7 +287,7 @@ if(MSVC)
   endif()
 endif()
 
-# Those are used for pkg-config and friends, so that the SDL2.pc, sdl2-config,
+# Those are used for pkg-config and friends, so that the sdl2.pc, sdl2-config,
 # etc. are created correctly.
 set(SDL_LIBS "-lSDL2")
 set(SDL_CFLAGS "")
@@ -312,7 +312,7 @@ if(CYGWIN)
     HAVE_GCC_NO_CYGWIN)
   set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS})
   if(HAVE_GCC_NO_CYGWIN)
-    list(APPEND EXTRA_LDFLAGS "-mno-cygwin")
+    list(APPEND EXTRA_LDFLAGS_BUILD "-mno-cygwin")
     list(APPEND SDL_LIBS "-mno-cygwin")
   endif()
   set(SDL_CFLAGS "${SDL_CFLAGS} -I/usr/include/mingw")
@@ -612,15 +612,16 @@ if(USE_GCC OR USE_CLANG)
   endif()
 
   if(APPLE)
-    list(APPEND EXTRA_LDFLAGS "-Wl,-undefined,error")
-    list(APPEND EXTRA_LDFLAGS "-Wl,-compatibility_version,${DYLIB_COMPATIBILITY_VERSION}")
-    list(APPEND EXTRA_LDFLAGS "-Wl,-current_version,${DYLIB_CURRENT_VERSION}")
+    # FIXME: use generator expression instead of appending to EXTRA_LDFLAGS_BUILD
+    list(APPEND EXTRA_LDFLAGS_BUILD "-Wl,-undefined,error")
+    list(APPEND EXTRA_LDFLAGS_BUILD "-Wl,-compatibility_version,${DYLIB_COMPATIBILITY_VERSION}")
+    list(APPEND EXTRA_LDFLAGS_BUILD "-Wl,-current_version,${DYLIB_CURRENT_VERSION}")
   elseif(NOT OPENBSD)
     set(CMAKE_REQUIRED_FLAGS "-Wl,--no-undefined")
     check_c_compiler_flag("" HAVE_NO_UNDEFINED)
     set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS})
     if(HAVE_NO_UNDEFINED AND NOT (USE_CLANG AND WINDOWS))
-      list(APPEND EXTRA_LDFLAGS "-Wl,--no-undefined")
+      list(APPEND EXTRA_LDFLAGS_BUILD "-Wl,--no-undefined")
     endif()
   endif()
 
@@ -1838,8 +1839,6 @@ elseif(WINDOWS)
   file(GLOB VERSION_SOURCES ${SDL2_SOURCE_DIR}/src/main/windows/*.rc)
   file(GLOB SDLMAIN_SOURCES ${SDL2_SOURCE_DIR}/src/main/windows/*.c)
   if(MINGW OR CYGWIN)
-    list(APPEND EXTRA_LIBS mingw32)
-    list(APPEND EXTRA_LDFLAGS "-mwindows")
     list(APPEND SDL_LIBS "-lmingw32" "-mwindows")
     if(NOT SDL2_DISABLE_SDL2MAIN)
       set(SDL_CFLAGS "${SDL_CFLAGS} -Dmain=SDL_main")
@@ -2850,7 +2849,7 @@ endif()
 message(STATUS "")
 message(STATUS " CFLAGS:        ${CMAKE_C_FLAGS}")
 message(STATUS " EXTRA_CFLAGS:  ${EXTRA_CFLAGS}")
-message(STATUS " EXTRA_LDFLAGS: ${EXTRA_LDFLAGS}")
+message(STATUS " EXTRA_LDFLAGS: ${EXTRA_LDFLAGS} ${EXTRA_LDFLAGS_BUILD}")
 message(STATUS " EXTRA_LIBS:    ${EXTRA_LIBS}")
 message(STATUS "")
 message(STATUS " Build Shared Library: ${SDL_SHARED}")
@@ -2897,6 +2896,14 @@ if(NOT WINDOWS_STORE AND NOT SDL2_DISABLE_SDL2MAIN)
   if (WIN32)
     target_link_libraries(SDL2main PRIVATE shell32)
   endif()
+  if(MINGW OR CYGWIN)
+    cmake_minimum_required(VERSION 3.13)
+    if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+      target_link_options(SDL2main PUBLIC "-Wl,--undefined=_WinMain@16")
+    else()
+      target_link_options(SDL2main PUBLIC "-Wl,--undefined=WinMain")
+    endif()
+  endif()
   if (NOT ANDROID)
     set_target_properties(SDL2main PROPERTIES DEBUG_POSTFIX "${SDL_CMAKE_DEBUG_POSTFIX}")
   endif()
@@ -2945,11 +2952,17 @@ if(SDL_SHARED)
     endif()
     set_target_properties(SDL2 PROPERTIES STATIC_LIBRARY_FLAGS "/NODEFAULTLIB")
   endif()
-  target_link_libraries(SDL2 PRIVATE ${EXTRA_LIBS} ${EXTRA_LDFLAGS})
+  # FIXME: if CMAKE_VERSION >= 3.13, use target_link_options for EXTRA_LDFLAGS
+  target_link_libraries(SDL2 PRIVATE ${EXTRA_LIBS} ${EXTRA_LDFLAGS} ${EXTRA_LDFLAGS_BUILD})
   target_include_directories(SDL2 BEFORE PRIVATE "${SDL2_BINARY_DIR}/include")
   target_include_directories(SDL2 PUBLIC "$<BUILD_INTERFACE:${SDL2_SOURCE_DIR}/include>;$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>;$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/SDL2>")
   # This picks up all the compiler options and such we've accumulated up to here.
   target_link_libraries(SDL2 PRIVATE $<BUILD_INTERFACE:sdl-build-options>)
+  if(MINGW OR CYGWIN)
+    if(NOT CMAKE_VERSION VERSION_LESS "3.13")
+      target_link_options(SDL2 PRIVATE -static-libgcc)
+    endif()
+  endif()
   if(NOT ANDROID)
     set_target_properties(SDL2 PROPERTIES DEBUG_POSTFIX "${SDL_CMAKE_DEBUG_POSTFIX}")
   endif()
@@ -2963,12 +2976,11 @@ if(SDL_STATIC)
   add_library(SDL2-static STATIC ${SOURCE_FILES})
   # alias target for in-tree builds
   add_library(SDL2::SDL2-static ALIAS SDL2-static)
-  if (NOT SDL_SHARED OR NOT WIN32 OR MINGW)
+  if(MSVC OR (WATCOM AND (WIN32 OR OS2)))
+    # Avoid conflict between the dll import library and the static library
+    set_target_properties(SDL2-static PROPERTIES OUTPUT_NAME "SDL2-static")
+  else()
     set_target_properties(SDL2-static PROPERTIES OUTPUT_NAME "SDL2")
-    # Note: Apparently, OUTPUT_NAME must really be unique; even when
-    # CMAKE_IMPORT_LIBRARY_SUFFIX or the like are given. Otherwise
-    # the static build may race with the import lib and one will get
-    # clobbered, when the suffix is realized via subsequent rename.
   endif()
   set_target_properties(SDL2-static PROPERTIES POSITION_INDEPENDENT_CODE ${SDL_STATIC_PIC})
   # Note: The clang toolset for Visual Studio does not support /NODEFAULTLIB.
@@ -2979,7 +2991,7 @@ if(SDL_STATIC)
   endif()
   # TODO: Win32 platforms keep the same suffix .lib for import and static
   # libraries - do we need to consider this?
-  target_link_libraries(SDL2-static PRIVATE ${EXTRA_LIBS} ${EXTRA_LDFLAGS})
+  target_link_libraries(SDL2-static PRIVATE ${EXTRA_LIBS} ${EXTRA_LDFLAGS} ${EXTRA_LDFLAGS_BUILD})
   target_include_directories(SDL2-static BEFORE PRIVATE "${SDL2_BINARY_DIR}/include")
   target_include_directories(SDL2-static PUBLIC "$<BUILD_INTERFACE:${SDL2_SOURCE_DIR}/include>" $<INSTALL_INTERFACE:include> $<INSTALL_INTERFACE:include/SDL2>)
   # This picks up all the compiler options and such we've accumulated up to here.
@@ -3047,6 +3059,10 @@ if(NOT SDL2_DISABLE_INSTALL)
   endif ()
 
   include(CMakePackageConfigHelpers)
+  configure_package_config_file(SDL2Config.cmake.in "${CMAKE_BINARY_DIR}/SDL2Config.cmake"
+    PATH_VARS CMAKE_INSTALL_PREFIX CMAKE_INSTALL_FULL_BINDIR CMAKE_INSTALL_FULL_INCLUDEDIR CMAKE_INSTALL_FULL_LIBDIR
+    INSTALL_DESTINATION ${PKG_PREFIX}
+  )
   write_basic_package_version_file("${CMAKE_BINARY_DIR}/SDL2ConfigVersion.cmake"
     VERSION ${SDL_VERSION}
     COMPATIBILITY AnyNewerVersion
@@ -3086,7 +3102,7 @@ if(NOT SDL2_DISABLE_INSTALL)
 
   install(
     FILES
-      ${CMAKE_CURRENT_SOURCE_DIR}/SDL2Config.cmake
+      ${CMAKE_CURRENT_BINARY_DIR}/SDL2Config.cmake
       ${CMAKE_BINARY_DIR}/SDL2ConfigVersion.cmake
     DESTINATION ${PKG_PREFIX}
     COMPONENT Devel
diff --git a/SDL2Config.cmake b/SDL2Config.cmake
deleted file mode 100644
index 39be60b639d..00000000000
--- a/SDL2Config.cmake
+++ /dev/null
@@ -1,122 +0,0 @@
-if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/SDL2Targets.cmake")
-  include("${CMAKE_CURRENT_LIST_DIR}/SDL2Targets.cmake")
-endif()
-if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/SDL2mainTargets.cmake")
-  include("${CMAKE_CURRENT_LIST_DIR}/SDL2mainTargets.cmake")
-endif()
-if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/SDL2staticTargets.cmake")
-  include("${CMAKE_CURRENT_LIST_DIR}/SDL2staticTargets.cmake")
-endif()
-if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/SDL2testTargets.cmake")
-  include("${CMAKE_CURRENT_LIST_DIR}/SDL2testTargets.cmake")
-endif()
-
-# on static-only builds create an alias
-if(NOT TARGET SDL2::SDL2 AND TARGET SDL2::SDL2-static)
-  if(CMAKE_VERSION VERSION_LESS "3.18")
-      # Aliasing local targets is not supported on CMake < 3.18, so make it global.
-      set_target_properties(SDL2::SDL2-static PROPERTIES IMPORTED_GLOBAL TRUE)
-  endif()
-  add_library(SDL2::SDL2 ALIAS SDL2::SDL2-static)
-endif()
-
-# provide ${SDL2_LIBRARIES}, ${SDL2_INCLUDE_DIRS} etc, like sdl2-config.cmake does,
-# for compatibility between SDL2 built with autotools and SDL2 built with CMake
-
-# the following seems to work on Windows for both MSVC and MINGW+MSYS and with both SDL2Config/Target.cmake
-# from vcpkg and from building myself with cmake from latest git
-# AND on Linux when building SDL2 (tested current git) with CMake
-
-# the headers are easy - but note that this adds both .../include/ and .../include/SDL2/
-# while the SDL2_INCLUDE_DIRS of sdl2-config.cmake only add ...include/SDL2/
-# But at least if building worked with sdl2-config.cmake it will also work with this.
-get_target_property(SDL2_INCLUDE_DIRS SDL2::SDL2 INTERFACE_INCLUDE_DIRECTORIES)
-
-# get the paths to the files to link against (.lib or .dll.a on Windows, .so or .a on Unix, ...) for both SDL2 and SDL2main
-
-# for the "normal"/release build they could be in lots of different properties..
-set(relprops IMPORTED_IMPLIB_RELEASE IMPORTED_IMPLIB_NOCONFIG IMPORTED_IMPLIB IMPORTED_IMPLIB_MINSIZEREL IMPORTED_IMPLIB_RELWITHDEBINFO
-             IMPORTED_LOCATION_RELEASE IMPORTED_LOCATION_NOCONFIG IMPORTED_LOCATION IMPORTED_LOCATION_MINSIZEREL IMPORTED_LOCATION_RELWITHDEBINFO)
-
-# fewer possibilities for debug builds
-set(dbgprops IMPORTED_IMPLIB_DEBUG IMPORTED_LOCATION_DEBUG)
-
-foreach(prop ${relprops})
-	get_target_property(sdl2implib SDL2::SDL2 ${prop})
-	if(sdl2implib)
-		#message("set sdl2implib from ${prop}")
-		break()
-	endif()
-endforeach()
-
-foreach(prop ${relprops})
-	get_target_property(sdl2mainimplib SDL2::SDL2main ${prop})
-	if(sdl2mainimplib)
-		#message("set sdl2mainimplib from ${prop}")
-		break()
-	endif()
-endforeach()
-
-foreach(prop ${dbgprops})
-	get_target_property(sdl2implibdbg SDL2::SDL2 ${prop})
-	if(sdl2implibdbg)
-		#message("set sdl2implibdbg from ${prop}")
-		break()
-	endif()
-endforeach()
-
-foreach(prop ${dbgprops})
-	get_target_property(sdl2mainimplibdbg SDL2::SDL2main ${prop})
-	if(sdl2mainimplibdbg)
-		#message("set sdl2mainimplibdbg from ${prop}")
-		break()
-	endif()
-endforeach()
-
-if( sdl2implib AND sdl2mainimplib AND sdl2implibdbg AND sdl2mainimplibdbg )
-	# we have both release and debug builds of SDL2 and SDL2main, so use this ugly
-	# generator expression in SDL2_LIBRARIES to support both in MSVC, depending on build type configured there
-	set(SDL2_LIBRARIES $<IF:$<CONFIG:Debug>,${sdl2mainimplibdbg},${sdl2mainimplib}>   $<IF:$<CONFIG:Debug>,${sdl2implibdbg},${sdl2implib}>)
-else()
-	if( (NOT sdl2implib) AND sdl2implibdbg ) # if we only have a debug version of the lib
-		set(sdl2implib ${sdl2implibdbg})
-	endif()
-	if( (NOT sdl2mainimplib) AND sdl2mainimplibdbg ) # if we only have a debug version of the lib
-		set(sdl2mainimplib ${sdl2mainimplibdbg})
-	endif()
-
-	if( sdl2implib AND sdl2mainimplib )
-		set(SDL2_LIBRARIES ${sdl2mainimplib}  ${sdl2implib})
-	elseif(WIN32 OR APPLE) # I think these platforms have a non-dummy SDLmain?
-		message(FATAL_ERROR, "SDL2::SDL2 and/or SDL2::SDL2main don't seem to contain any kind of IMPORTED_IMPLIB* or IMPORTED_LOCATION*")
-	elseif(sdl2implib) # on other platforms just libSDL2 will hopefully do?
-		set(SDL2_LIBRARIES ${sdl2implib})
-		message(STATUS, "No SDL2main lib not found, I hope you don't need it..")
-	else()
-		message(FATAL_ERROR, "SDL2::SDL2 doesn't seem to contain any kind of lib to link against in IMPORTED_IMPLIB* or IMPORTED_LOCATION*")
-	endif()
-
-	# TODO: should something like INTERFACE_LINK_LIBRARIES be appended? or wherever -mwindows and things like that
-	#       might be defined (if they were defined by the CMake build at all; autotools has @SDL_RLD_FLAGS@ @SDL_LIBS@)?
-	#       LINK_DEPENDS? LINK_FLAGS?
-
-endif()
-
-get_filename_component(SDL2_LIBDIR ${sdl2implib} PATH)
-
-# NOTE: SDL2_LIBRARIES now looks like "c:/path/to/SDL2main.lib;c:/path/to/SDL2.lib"
-#       which is different to what it looks like when coming from sdl2-config.cmake
-#       (there it's more like "-L${SDL2_LIBDIR} -lSDL2main -lSDL2" - and also -lmingw32 and -mwindows)
-#       This seems to work with both MSVC and MinGW though, while the other only worked with MinGW
-#   On Linux it looks like "/tmp/sdl2inst/lib/libSDL2main.a;/tmp/sdl2inst/lib/libSDL2-2.0.so.0.14.1" which also seems to work
-
-# the exec prefix is one level up from lib/ - TODO: really, always? at least on Linux there's /usr/lib/x86_64-bla-blub/libSDL2-asdf.so.0 ..
-get_filename_component(SDL2_EXEC_PREFIX ${SDL2_LIBDIR} PATH)
-set(SDL2_PREFIX ${SDL2_EXEC_PREFIX}) # TODO: could this be somewhere else? parent dir of include or sth?
-
-unset(sdl2implib)
-unset(sdl2mainimplib)
-unset(sdl2implibdbg)
-unset(sdl2mainimplibdbg)
-unset(relprops)
-unset(dbgprops)
diff --git a/SDL2Config.cmake.in b/SDL2Config.cmake.in
new file mode 100644
index 00000000000..99344b2873a
--- /dev/null
+++ b/SDL2Config.cmake.in
@@ -0,0 +1,60 @@
+# sdl2 cmake project-config input for CMakeLists.txt script
+
+include(FeatureSummary)
+set_package_properties(SDL2 PROPERTIES
+  URL "https://www.libsdl.org/"
+  DESCRIPTION "low level access to audio, keyboard, mouse, joystick, and graphics hardware"
+)
+
+@PACKAGE_INIT@
+
+set(SDL2_FOUND TRUE)
+
+if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/SDL2Targets.cmake")
+  include("${CMAKE_CURRENT_LIST_DIR}/SDL2Targets.cmake")
+  set(SDL2_SDL2_FOUND TRUE)
+endif()
+if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/SDL2staticTargets.cmake")
+  include("${CMAKE_CURRENT_LIST_DIR}/SDL2staticTargets.cmake")
+  set(SDL2_SDL2-static_FOUND TRUE)
+endif()
+if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/SDL2mainTargets.cmake")
+  include("${CMAKE_CURRENT_LIST_DIR}/SDL2mainTargets.cmake")
+  set(SDL2_SDL2main_FOUND TRUE)
+endif()
+if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/SDL2testTargets.cmake")
+  include("${CMAKE_CURRENT_LIST_DIR}/SDL2testTargets.cmake")
+  set(SDL2_SDL2test_FOUND TRUE)
+endif()
+
+check_required_components(SDL2)
+
+# Create SDL2::SDL2 alias for static-only builds
+if(NOT TARGET SDL2::SDL2 AND TARGET SDL2::SDL2-static)
+  if(CMAKE_VERSION VERSION_LESS "3.18")
+    # Aliasing local targets is not supported on CMake < 3.18, so make it global.
+    set_target_properties(SDL2::SDL2-static PROPERTIES IMPORTED_GLOBAL TRUE)
+  endif()
+  add_library(SDL2::SDL2 ALIAS SDL2::SDL2-static)
+endif()
+
+# For compatibility with autotools sdl2-config.cmake, provide SDL2_* variables.
+
+set(SDL2_PREFIX "@PACKAGE_CMAKE_INSTALL_PREFIX@")
+set(SDL2_EXEC_PREFIX "@PACKAGE_CMAKE_INSTALL_PREFIX@")
+set(SDL2_INCLUDE_DIR "@PACKAGE_CMAKE_INSTALL_FULL_INCLUDEDIR@/SDL2")
+set(SDL2_INCLUDE_DIRS "@PACKAGE_CMAKE_INSTALL_FULL_INCLUDEDIR@;@PACKAGE_CMAKE_INSTALL_FULL_INCLUDEDIR@/SDL2")
+set(SDL2_BINDIR "@PACKAGE_CMAKE_INSTALL_FULL_BINDIR@")
+set(SDL2_LIBDIR "@PACKAGE_CMAKE_INSTALL_FULL_LIBDIR@")
+set(SDL2_LIBRARIES SDL2::SDL2)
+set(SDL2_STATIC_LIBRARIES SDL2::SDL2-static)
+set(SDL2_STATIC_PRIVATE_LIBS)
+
+set(SDL2MAIN_LIBRARY)
+if(TARGET SDL2::SDL2main)
+  set(SDL2MAIN_LIBRARY SDL2::SDL2main)
+  list(INSERT SDL2_LIBRARIES 0 SDL2::SDL2main)
+  list(INSERT SDL2_STATIC_LIBRARIES 0 SDL2::SDL2main)
+endif()
+
+set(SDL2TEST_LIBRARY SDL2::SDL2test)