SDL_gpu_shadercross: ci: Upload artifacts

From 406484eba79c3e1d20318bc8857221233f842c54 Mon Sep 17 00:00:00 2001
From: Anonymous Maarten <[EMAIL REDACTED]>
Date: Fri, 25 Oct 2024 21:25:12 +0200
Subject: [PATCH] ci: Upload artifacts

---
 .github/workflows/main.yml        |  33 ++++++-
 CMakeLists.txt                    |  27 +++++-
 cmake/CPackProjectConfig.cmake.in |  37 +++++++
 cmake/sdlcpu.cmake                | 156 ++++++++++++++++++++++++++++++
 cmake/sdlplatform.cmake           | 106 ++++++++++++++++++++
 5 files changed, 351 insertions(+), 8 deletions(-)
 create mode 100644 cmake/CPackProjectConfig.cmake.in
 create mode 100644 cmake/sdlcpu.cmake
 create mode 100644 cmake/sdlplatform.cmake

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 40a272b..2bc411b 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -15,10 +15,10 @@ jobs:
       fail-fast: false
       matrix:
         platform:
-          - { name: Windows (MSVC),       os: windows-2019, shell: sh, msvc: true }
-          - { name: Windows (mingw64),    os: windows-latest, shell: 'msys2 {0}', msystem: mingw64, msys-env: mingw-w64-x86_64 }
-          - { name: Linux,                os: ubuntu-20.04,   shell: sh }
-          - { name: Macos,                os: macos-latest,   shell: sh }
+          - { name: Windows (MSVC),       os: windows-2019, shell: sh, msvc: true, artifact: 'SDL_gpu_shadercross-VC-x64' }
+          - { name: Windows (mingw64),    os: windows-latest, shell: 'msys2 {0}', msystem: mingw64, msys-env: mingw-w64-x86_64, artifact: 'SDL_gpu_shadercross-mingw64' }
+          - { name: Linux,                os: ubuntu-20.04,   shell: sh, artifact: 'SDL_gpu_shadercross-linux-x64' }
+          - { name: Macos,                os: macos-latest,   shell: sh, artifact: 'SDL_gpu_shadercross-macos-x64' }
 
 
     steps:
@@ -52,9 +52,32 @@ jobs:
 
       - name: Configure (CMake)
         run: |
-          cmake -S . -B build -GNinja -DBUILD_STATIC=ON -DBUILD_CLI=ON -DENABLE_WERROR=ON -DCMAKE_POLICY_DEFAULT_CMP0074=NEW
+          cmake -S . -B build -GNinja \
+            -DBUILD_STATIC=ON \
+            -DBUILD_CLI=ON \
+            -DENABLE_WERROR=ON \
+            -DENABLE_INSTALL=ON \
+            -DENABLE_INSTALL_CPACK=ON \
+            -DCMAKE_INSTALL_PREFIX=prefix
 
       - name: Build (CMake)
         id: build
         run: |
           cmake --build build --config Release --parallel --verbose
+
+      - name: Install (CMake)
+        if: ${{ always() && steps.build.outcome == 'success' }}
+        run: |
+          cmake --install build/ --config Release
+      - name: Package (CPack)
+        id: package
+        if: ${{ always() && steps.build.outcome == 'success' }}
+        run: |
+          cmake --build build/ --target package
+
+      - uses: actions/upload-artifact@v4
+        if: ${{ always() && steps.package.outcome == 'success' }}
+        with:
+          if-no-files-found: error
+          name: ${{ matrix.platform.artifact }}
+          path: build/dist/SDL*
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e9a26e5..b20855c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,17 +10,20 @@ set(SDL_REQUIRED_VERSION "3.1.3")
 
 project(SDL_gpu_shadercross LANGUAGES C VERSION "${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}")
 
-include("${CMAKE_CURRENT_LIST_DIR}/cmake/PrivateSdlFunctions.cmake")
 include(CMakeDependentOption)
+include("${CMAKE_CURRENT_LIST_DIR}/cmake/PrivateSdlFunctions.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/cmake/sdlcpu.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/cmake/sdlplatform.cmake")
 
 find_package(SDL3 REQUIRED COMPONENTS SDL3-shared)
 
 # Options
 option(BUILD_STATIC "Build static library" ON)
 option(BUILD_CLI "Build command line executable" ON)
+cmake_dependent_option(BUILD_CLI_STATIC "Link CLI with static libraries" OFF "BUILD_CLI;BUILD_STATIC;TARGET SDL3::SDL3-static" OFF)
 option(ENABLE_WERROR "Enable Werror" OFF)
 option(ENABLE_INSTALL "Enable installation" OFF)
-cmake_dependent_option(BUILD_CLI_STATIC "Link CLI with static libraries" OFF "BUILD_CLI;BUILD_STATIC;TARGET SDL3::SDL3-static" OFF)
+cmake_dependent_option(ENABLE_INSTALL_CPACK "Enable CPack installation" OFF "ENABLE_INSTALL" OFF)
 
 sdl_calculate_derived_version_variables(${MAJOR_VERSION} ${MINOR_VERSION} ${MICRO_VERSION})
 
@@ -117,6 +120,7 @@ if(BUILD_CLI)
 endif()
 
 if(ENABLE_INSTALL)
+	include(GNUInstallDirs)
 	if(WIN32 AND NOT MINGW)
 		set(INSTALL_CMAKEDIR_ROOT_DEFAULT "cmake")
 	else()
@@ -131,7 +135,6 @@ if(ENABLE_INSTALL)
 		set(SDLGPUSHADERCROSS_INSTALL_CMAKEDIR "${SDLGPUSHADERCROSS_INSTALL_CMAKEDIR_ROOT}/SDL_gpu_shadercross")
 	endif()
 
-	include(GNUInstallDirs)
 	if(TARGET SDL_gpu_shadercross-shared)
 		install(TARGETS SDL_gpu_shadercross-shared EXPORT SDL_gpu_shadercross-shared-export
 			ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT devel
@@ -161,6 +164,9 @@ if(ENABLE_INSTALL)
 		FILES "${CMAKE_CURRENT_SOURCE_DIR}/include/SDL_gpu_shadercross.h"
 		DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" COMPONENT DEVEL
 	)
+	if(BUILD_CLI)
+		install(TARGETS shadercross RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
+	endif()
 
 	include(CMakePackageConfigHelpers)
 	configure_package_config_file(cmake/SDL_gpu_shadercrossConfig.cmake.in SDL_gpu_shadercrossConfig.cmake
@@ -193,4 +199,19 @@ if(ENABLE_INSTALL)
 		DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/licenses/${PROJECT_NAME}"
 		COMPONENT library
 	)
+	if(ENABLE_INSTALL_CPACK)
+		SDL_DetectTargetCPUArchitectures(SDL_CPU_NAMES)
+		SDL_DetectCMakePlatform()
+		if(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_gpu_shadercross-${PROJECT_VERSION}-src")
+		set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}/dist")
+		include(CPack)
+	endif()
 endif()
diff --git a/cmake/CPackProjectConfig.cmake.in b/cmake/CPackProjectConfig.cmake.in
new file mode 100644
index 0000000..4c7ce7d
--- /dev/null
+++ b/cmake/CPackProjectConfig.cmake.in
@@ -0,0 +1,37 @@
+if(CPACK_PACKAGE_FILE_NAME MATCHES ".*-src$")
+    message(FATAL_ERROR "Creating source archives is not supported.")
+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@")
+list(SORT SDL_CPU_NAMES)
+
+string(TOLOWER "${SDL_CMAKE_PLATFORM}" SDL_CMAKE_PLATFORM)
+string(TOLOWER "${SDL_CPU_NAMES}" SDL_CPU_NAMES)
+if(lower_sdl_cmake_platform STREQUAL lower_sdl_cpu_names)
+    set(SDL_CPU_NAMES_WITH_DASHES)
+endif()
+
+string(REPLACE ";" "-" SDL_CPU_NAMES_WITH_DASHES "${SDL_CPU_NAMES}")
+if(SDL_CPU_NAMES_WITH_DASHES)
+    set(SDL_CPU_NAMES_WITH_DASHES "-${SDL_CPU_NAMES_WITH_DASHES}")
+endif()
+
+set(MSVC @MSVC@)
+set(MINGW @MINGW@)
+if(MSVC)
+    set(SDL_CMAKE_PLATFORM "${SDL_CMAKE_PLATFORM}-VC")
+elseif(MINGW)
+    set(SDL_CMAKE_PLATFORM "${SDL_CMAKE_PLATFORM}-mingw")
+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 "@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/sdlcpu.cmake b/cmake/sdlcpu.cmake
new file mode 100644
index 0000000..d63a57f
--- /dev/null
+++ b/cmake/sdlcpu.cmake
@@ -0,0 +1,156 @@
+function(SDL_DetectTargetCPUArchitectures DETECTED_ARCHS)
+
+  set(known_archs EMSCRIPTEN ARM32 ARM64 ARM64EC LOONGARCH64 POWERPC32 POWERPC64 X86 X64)
+
+  if(APPLE AND CMAKE_OSX_ARCHITECTURES)
+    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)
+      if(osx_arch STREQUAL "x86_64")
+        set(SDL_CPU_X64 "1")
+        list(APPEND detected_archs "X64")
+      elseif(osx_arch STREQUAL "arm64")
+        set(SDL_CPU_ARM64 "1")
+        list(APPEND detected_archs "ARM64")
+      endif()
+    endforeach()
+    set("${DETECTED_ARCHS}" "${detected_archs}" PARENT_SCOPE)
+    return()
+  endif()
+
+  set(detected_archs)
+  foreach(known_arch IN LISTS known_archs)
+    if(SDL_CPU_${known_arch})
+      list(APPEND detected_archs "${known_arch}")
+    endif()
+  endforeach()
+
+  if(detected_archs)
+    set("${DETECTED_ARCHS}" "${detected_archs}" PARENT_SCOPE)
+    return()
+  endif()
+
+  set(arch_check_ARM32 "defined(__arm__) || defined(_M_ARM)")
+  set(arch_check_ARM64 "defined(__aarch64__) || defined(_M_ARM64)")
+  set(arch_check_ARM64EC "defined(_M_ARM64EC)")
+  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)) && !defined(_M_ARM64EC)")
+
+  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_${known_arch} \"0\"
+#endif
+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 = 0;
+${src_main}
+  return result;
+}")
+
+  if(CMAKE_C_COMPILER)
+    set(ext ".c")
+  elseif(CMAKE_CXX_COMPILER)
+    set(ext ".cpp")
+  else()
+    enable_language(C)
+    set(ext ".c")
+  endif()
+  set(path_src_arch_detect "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeTmp/SDL_detect_arch${ext}")
+  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}")
+
+  include(CMakePushCheckState)
+
+  set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
+
+  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")
+  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()
+
+    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()
diff --git a/cmake/sdlplatform.cmake b/cmake/sdlplatform.cmake
new file mode 100644
index 0000000..ebb2077
--- /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()