SDL_image: cmake: create binary packages with cpack

From 97b6d9807e351b9b8688dba95a0070d9433a59cb Mon Sep 17 00:00:00 2001
From: Anonymous Maarten <[EMAIL REDACTED]>
Date: Thu, 14 Dec 2023 20:16:07 +0100
Subject: [PATCH] cmake: create binary packages with cpack

---
 .github/workflows/main.yml        |  20 ++++--
 CMakeLists.txt                    |  30 +++++++--
 cmake/CPackProjectConfig.cmake.in |   3 +-
 cmake/CheckCPUArchitecture.cmake  |  42 ++++++++++++
 cmake/sdlplatform.cmake           | 106 ++++++++++++++++++++++++++++++
 5 files changed, 191 insertions(+), 10 deletions(-)
 create mode 100644 cmake/CheckCPUArchitecture.cmake
 create mode 100644 cmake/sdlplatform.cmake

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index f5de31ce..79c42d75 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -15,13 +15,13 @@ jobs:
       fail-fast: false
       matrix:
         platform:
-        - { name: Windows (MSVC),    os: windows-latest, shell: sh,  vendored: true, msvc: 1, shared: 1, static: 0,
+        - { name: Windows (MSVC),    os: windows-latest, shell: sh,  vendored: true, msvc: 1, shared: 1, static: 0, artifact: 'SDL3_image-VC-x64',
             cmake: '-DSDL3IMAGE_BACKEND_STB=OFF -DPerl_ROOT=C:/Strawberry/perl/bin/ -GNinja -DCMAKE_POLICY_DEFAULT_CMP0141=NEW -DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=ProgramDatabase -DCMAKE_EXE_LINKER_FLAGS=-DEBUG -DCMAKE_SHARED_LINKER_FLAGS=-DEBUG' }
-        - { name: Windows (mingw64), os: windows-latest, shell: 'msys2 {0}', vendored: false, msystem: mingw64, msys-env: mingw-w64-x86_64, shared: 1, static: 0,
+        - { name: Windows (mingw64), os: windows-latest, shell: 'msys2 {0}', vendored: false, msystem: mingw64, msys-env: mingw-w64-x86_64, shared: 1, static: 0, artifact: 'SDL3_image-mingw64',
             cmake: '-DSDL3IMAGE_BACKEND_STB=OFF -DSDL3IMAGE_BACKEND_WIC=OFF  -DSDL3IMAGE_AVIF=ON -G "Ninja Multi-Config"' }
-        - { name: Linux,             os: ubuntu-latest,  shell: sh,  vendored: false, cmake: '-GNinja', shared: 1, static: 0, nojxl: true }
-        - { name: 'Linux (static)',  os: ubuntu-latest,  shell: sh,  vendored: true, cmake: '-DBUILD_SHARED_LIBS=OFF -GNinja', shared: 0, static: 1 }
-        - { name: Macos,             os: macos-latest,   shell: sh,  vendored: false, cmake: '-GNinja', shared: 1, static: 0 }
+        - { name: Linux,             os: ubuntu-latest,  shell: sh,  vendored: false, cmake: '-GNinja', shared: 1, static: 0, nojxl: true, artifact: 'SDL3_image-linux-x64' }
+        - { name: 'Linux (static)',  os: ubuntu-latest,  shell: sh,  vendored: true, cmake: '-DBUILD_SHARED_LIBS=OFF -GNinja', shared: 0, static: 1, artifact: 'SDL3_image-static-linux-x64' }
+        - { name: Macos,             os: macos-latest,   shell: sh,  vendored: false, cmake: '-GNinja', shared: 1, static: 0, artifact: 'SDL3_image-macos' }
 
     steps:
 
@@ -166,6 +166,10 @@ jobs:
         cmake --install build/ --config Release
         echo "SDL3_image_ROOT=$(pwd)/prefix_cmake" >> $GITHUB_ENV
         ( cd prefix_cmake; find . ) | LC_ALL=C sort -u
+    - name: Package (CPack)
+      if: ${{ always() && steps.build.outcome == 'success' }}
+      run: |
+        cmake --build build/ --target package
     - name: Upload artifacts
       if: ${{ failure() && runner.os == 'Linux' }}
       uses: actions/upload-artifact@v3
@@ -184,3 +188,9 @@ jobs:
           -DTEST_SHARED=${{ matrix.platform.shared }} \
           -DTEST_STATIC=${{ matrix.platform.static }}
         cmake --build cmake_config_build --verbose
+    - uses: actions/upload-artifact@v3
+      if: ${{ always() && steps.build.outcome == 'success' }}
+      with:
+        if-no-files-found: error
+        name: ${{ matrix.platform.artifact }}
+        path: build/dist/SDL3_image*
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5d9d7e3c..401400da 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -17,9 +17,11 @@ project(SDL3_image
     VERSION "${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}"
 )
 
-include("${SDL3_image_SOURCE_DIR}/cmake/GetGitRevisionDescription.cmake" )
-include("${SDL3_image_SOURCE_DIR}/cmake/PrivateSdlFunctions.cmake" )
-include("${SDL3_image_SOURCE_DIR}/cmake/sdlmanpages.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/cmake/CheckCPUArchitecture.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/cmake/GetGitRevisionDescription.cmake" )
+include("${CMAKE_CURRENT_LIST_DIR}/cmake/PrivateSdlFunctions.cmake" )
+include("${CMAKE_CURRENT_LIST_DIR}/cmake/sdlplatform.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/cmake/sdlmanpages.cmake")
 sdl_calculate_derived_version_variables(${MAJOR_VERSION} ${MINOR_VERSION} ${MICRO_VERSION})
 
 message(STATUS "Configuring ${PROJECT_NAME} ${PROJECT_VERSION}")
@@ -61,6 +63,7 @@ option(CMAKE_POSITION_INDEPENDENT_CODE "Build static libraries with -fPIC" ON)
 option(BUILD_SHARED_LIBS "Build the library as a shared library" ON)
 
 cmake_dependent_option(SDL3IMAGE_INSTALL "Enable SDL3_image install target" ${SDL3IMAGE_ROOTPROJECT} "${sdl3image_install_enableable}" OFF)
+cmake_dependent_option(SDL3IMAGE_INSTALL_CPACK "Create binary SDL3_image archive using CPack" ${SDL3IMAGE_ROOTPROJECT} "SDL3IMAGE_INSTALL" OFF)
 cmake_dependent_option(SDL3IMAGE_INSTALL_MAN "Install man pages for SDL3_image" ${SDL3IMAGE_ROOTPROJECT} "SDL3IMAGE_INSTALL" OFF)
 option(SDL3IMAGE_DEPS_SHARED "Load dependencies dynamically" ON)
 option(SDL3IMAGE_VENDORED "Use vendored third-party libraries" ${vendored_default})
@@ -195,6 +198,9 @@ if(NOT TARGET SDL3::Headers OR NOT TARGET ${sdl3_target_name})
     find_package(SDL3 ${SDL_REQUIRED_VERSION} REQUIRED COMPONENTS ${sdl_required_components})
 endif()
 
+SDL_DetectCPUArchitecture()
+SDL_DetectCMakePlatform()
+
 # Set PROJECT_VERSION of subprojects to "" if it's project call does not set VERSION
 cmake_policy(SET CMP0048 NEW)
 
@@ -793,7 +799,7 @@ if(SDL3IMAGE_INSTALL)
         set(pdbdir "${CMAKE_INSTALL_LIBDIR}")
     endif()
     if(MSVC)
-        SDL_install_pdb("${sdl3_image_target_Name}" "${pdbdir}")
+        SDL_install_pdb("${sdl3_image_target_name}" "${pdbdir}")
     endif()
 
     if(INSTALL_EXTRA_TARGETS)
@@ -870,6 +876,22 @@ if(SDL3IMAGE_INSTALL)
         COMPONENT library
     )
 
+    if(SDL3IMAGE_INSTALL_CPACK)
+        if(SDL2COMPAT_FRAMEWORK)
+            set(CPACK_GENERATOR "DragNDrop")
+        elseif(MSVC)
+            set(CPACK_GENERATOR "ZIP")
+        else()
+            set(CPACK_GENERATOR "TGZ")
+        endif()
+        configure_file(cmake/CPackProjectConfig.cmake.in CPackProjectConfig.cmake @ONLY)
+        set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_BINARY_DIR}/CPackProjectConfig.cmake")
+        # CPACK_SOURCE_PACKAGE_FILE_NAME must end with "-src" (so we can block creating a source archive)
+        set(CPACK_SOURCE_PACKAGE_FILE_NAME "SDL${PROJECT_VERSION_MAJOR}-${PROJECT_VERSION}-src")
+        set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}/dist")
+        include(CPack)
+    endif()
+
     if(SDL3IMAGE_INSTALL_MAN)
         sdl_get_git_revision_hash(SDL3IMAGE_REVISION)
         SDL_generate_manpages(
diff --git a/cmake/CPackProjectConfig.cmake.in b/cmake/CPackProjectConfig.cmake.in
index fd1061a1..735e2ea2 100644
--- a/cmake/CPackProjectConfig.cmake.in
+++ b/cmake/CPackProjectConfig.cmake.in
@@ -3,6 +3,7 @@ if(CPACK_PACKAGE_FILE_NAME MATCHES ".*-src$")
 endif()
 
 set(PROJECT_NAME "@PROJECT_NAME@")
+set(PROJECT_VERSION "@PROJECT_VERSION@")
 set(PROJECT_SOURCE_DIR "@PROJECT_SOURCE_DIR@")
 set(SDL_CMAKE_PLATFORM "@SDL_CMAKE_PLATFORM@")
 set(SDL_CPU_NAMES "@SDL_CPU_NAMES@")
@@ -30,7 +31,7 @@ endif()
 set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}-${SDL_CMAKE_PLATFORM}${SDL_CPU_NAMES_WITH_DASHES}")
 
 if(CPACK_GENERATOR STREQUAL "DragNDrop")
-    set(CPACK_DMG_VOLUME_NAME "SDL@PROJECT_VERSION_MAJOR@ @PROJECT_VERSION@")
+    set(CPACK_DMG_VOLUME_NAME "@PROJECT_NAME@ @PROJECT_VERSION@")
     # FIXME: use pre-built/create .DS_Store through AppleScript (CPACK_DMG_DS_STORE/CPACK_DMG_DS_STORE_SETUP_SCRIPT)
     set(CPACK_DMG_DS_STORE "${PROJECT_SOURCE_DIR}/Xcode/SDL/pkg-support/resources/SDL_DS_Store")
 endif()
diff --git a/cmake/CheckCPUArchitecture.cmake b/cmake/CheckCPUArchitecture.cmake
new file mode 100644
index 00000000..1eebbd4f
--- /dev/null
+++ b/cmake/CheckCPUArchitecture.cmake
@@ -0,0 +1,42 @@
+include(CheckCSourceCompiles)
+include(CMakePushCheckState)
+
+function(_internal_check_cpu_architecture macro_check NAME VARIABLE)
+  cmake_push_check_state()
+  string(TOUPPER "${NAME}" UPPER_NAME)
+  set(CACHE_VARIABLE "CHECK_CPU_ARCHITECTURE_${UPPER_NAME}")
+  set(test_src "
+int main(int argc, char *argv[]) {
+#if ${macro_check}
+  return 0;
+#else
+  choke
+#endif
+}
+")
+  check_c_source_compiles("${test_src}" "${CACHE_VARIABLE}")
+  cmake_pop_check_state()
+  if(${CACHE_VARIABLE})
+    set(${VARIABLE} "TRUE" PARENT_SCOPE)
+  else()
+    set(${VARIABLE} "FALSE" PARENT_SCOPE)
+  endif()
+endfunction()
+
+function(check_cpu_architecture ARCH VARIABLE)
+  if(ARCH STREQUAL "x86")
+    _internal_check_cpu_architecture("defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) ||defined( __i386) || defined(_M_IX86)" x86 ${VARIABLE})
+  elseif(ARCH STREQUAL "x64")
+    _internal_check_cpu_architecture("defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)" x64 ${VARIABLE})
+  elseif(ARCH STREQUAL "arm32")
+    _internal_check_cpu_architecture("defined(__arm__) || defined(_M_ARM)" arm32 ${VARIABLE})
+  elseif(ARCH STREQUAL "arm64")
+    _internal_check_cpu_architecture("defined(__aarch64__) || defined(_M_ARM64)" arm64 ${VARIABLE})
+  elseif(ARCH STREQUAL "loongarch64")
+    _internal_check_cpu_architecture("defined(__loongarch64)" loongarch64 ${VARIABLE})
+  else()
+    message(WARNING "Unknown CPU architectures (${ARCH}).")
+    set(${VARIABLE} FALSE)
+  endif()
+  set("${VARIABLE}" "${${VARIABLE}}" PARENT_SCOPE)
+endfunction()
diff --git a/cmake/sdlplatform.cmake b/cmake/sdlplatform.cmake
new file mode 100644
index 00000000..ebb2077f
--- /dev/null
+++ b/cmake/sdlplatform.cmake
@@ -0,0 +1,106 @@
+macro(SDL_DetectCMakePlatform)
+  set(SDL_CMAKE_PLATFORM )
+  # Get the platform
+  if(WIN32)
+    set(SDL_CMAKE_PLATFORM Windows)
+  elseif(PSP)
+    set(SDL_CMAKE_PLATFORM psp)
+  elseif(APPLE)
+    if(CMAKE_SYSTEM_NAME MATCHES ".*Darwin.*")
+      set(SDL_CMAKE_PLATFORM Darwin)
+    elseif(CMAKE_SYSTEM_NAME MATCHES ".*MacOS.*")
+      set(SDL_CMAKE_PLATFORM MacosX)
+    elseif(CMAKE_SYSTEM_NAME MATCHES ".*tvOS.*")
+      set(SDL_CMAKE_PLATFORM tvOS)
+    elseif(CMAKE_SYSTEM_NAME MATCHES ".*iOS.*")
+      set(SDL_CMAKE_PLATFORM iOS)
+    endif()
+  elseif(CMAKE_SYSTEM_NAME MATCHES "Haiku.*")
+    set(SDL_CMAKE_PLATFORM Haiku)
+  elseif(NINTENDO_3DS)
+    set(SDL_CMAKE_PLATFORM n3ds)
+  elseif(PS2)
+    set(SDL_CMAKE_PLATFORM ps2)
+  elseif(VITA)
+    set(SDL_CMAKE_PLATFORM Vita)
+  elseif(CMAKE_SYSTEM_NAME MATCHES ".*Linux")
+    set(SDL_CMAKE_PLATFORM Linux)
+  elseif(CMAKE_SYSTEM_NAME MATCHES "kFreeBSD.*")
+    set(SDL_CMAKE_PLATFORM FreeBSD)
+  elseif(CMAKE_SYSTEM_NAME MATCHES "kNetBSD.*|NetBSD.*")
+    set(SDL_CMAKE_PLATFORM NetBSD)
+  elseif(CMAKE_SYSTEM_NAME MATCHES "kOpenBSD.*|OpenBSD.*")
+    set(SDL_CMAKE_PLATFORM OpenBSD)
+  elseif(CMAKE_SYSTEM_NAME MATCHES ".*GNU.*")
+    set(SDL_CMAKE_PLATFORM GNU)
+  elseif(CMAKE_SYSTEM_NAME MATCHES ".*BSDI.*")
+    set(SDL_CMAKE_PLATFORM BSDi)
+  elseif(CMAKE_SYSTEM_NAME MATCHES "DragonFly.*|FreeBSD")
+    set(SDL_CMAKE_PLATFORM FreeBSD)
+  elseif(CMAKE_SYSTEM_NAME MATCHES "SYSV5.*")
+    set(SDL_CMAKE_PLATFORM SYSV5)
+  elseif(CMAKE_SYSTEM_NAME MATCHES "Solaris.*|SunOS.*")
+    set(SDL_CMAKE_PLATFORM Solaris)
+  elseif(CMAKE_SYSTEM_NAME MATCHES "HP-UX.*")
+    set(SDL_CMAKE_PLATFORM HPUX)
+  elseif(CMAKE_SYSTEM_NAME MATCHES "AIX.*")
+    set(SDL_CMAKE_PLATFORM AIX)
+  elseif(CMAKE_SYSTEM_NAME MATCHES "Minix.*")
+    set(SDL_CMAKE_PLATFORM Minix)
+  elseif(CMAKE_SYSTEM_NAME MATCHES "Android.*")
+    set(SDL_CMAKE_PLATFORM Android)
+  elseif(CMAKE_SYSTEM_NAME MATCHES "Emscripten.*")
+    set(SDL_CMAKE_PLATFORM Emscripten)
+  elseif(CMAKE_SYSTEM_NAME MATCHES "QNX.*")
+    set(SDL_CMAKE_PLATFORM QNX)
+  elseif(CMAKE_SYSTEM_NAME MATCHES "BeOS.*")
+    message(FATAL_ERROR "BeOS support has been removed as of SDL 2.0.2.")
+  endif()
+
+  if(SDL_CMAKE_PLATFORM)
+    string(TOUPPER "${SDL_CMAKE_PLATFORM}" _upper_platform)
+    set(${_upper_platform} TRUE)
+  else()
+    set(SDL_CMAKE_PLATFORM} "unknown")
+  endif()
+endmacro()
+
+function(SDL_DetectCPUArchitecture)
+  set(sdl_cpu_names)
+  if(APPLE AND CMAKE_OSX_ARCHITECTURES)
+    foreach(osx_arch ${CMAKE_OSX_ARCHITECTURES})
+      if(osx_arch STREQUAL "x86_64")
+        list(APPEND sdl_cpu_names "x64")
+      elseif(osx_arch STREQUAL "arm64")
+        list(APPEND sdl_cpu_names "arm64")
+      endif()
+    endforeach()
+  endif()
+
+  set(sdl_known_archs x64 x86 arm64 arm32 emscripten powerpc64 powerpc32 loongarch64)
+  if(NOT sdl_cpu_names)
+    set(found FALSE)
+    foreach(sdl_known_arch ${sdl_known_archs})
+      if(NOT found)
+        string(TOUPPER "${sdl_known_arch}" sdl_known_arch_upper)
+        set(var_name "SDL_CPU_${sdl_known_arch_upper}")
+        check_cpu_architecture(${sdl_known_arch} ${var_name})
+        if(${var_name})
+          list(APPEND sdl_cpu_names ${sdl_known_arch})
+          set(found TRUE)
+        endif()
+      endif()
+    endforeach()
+  endif()
+
+  foreach(sdl_known_arch ${sdl_known_archs})
+    string(TOUPPER "${sdl_known_arch}" sdl_known_arch_upper)
+    set(var_name "SDL_CPU_${sdl_known_arch_upper}")
+    if(sdl_cpu_names MATCHES "(^|;)${sdl_known_arch}($|;)")  # FIXME: use if(IN_LIST)
+      set(${var_name} 1 PARENT_SCOPE)
+    else()
+      set(${var_name} 0 PARENT_SCOPE)
+    endif()
+  endforeach()
+  set(SDL_CPU_NAMES ${sdl_cpu_names} PARENT_SCOPE)
+endfunction()