SDL: release: create arm64 Visual Studio binaries

From 86b2f441c07ef1dbaebca5df3502429693fe5355 Mon Sep 17 00:00:00 2001
From: Anonymous Maarten <[EMAIL REDACTED]>
Date: Wed, 22 May 2024 22:44:16 +0200
Subject: [PATCH] release: create arm64 Visual Studio binaries

[skip ci]
---
 .github/workflows/release.yml                 | 12 ++-
 .../cmake/sdl3-config-version.cmake           |  6 +-
 VisualC/pkg-support/cmake/sdl3-config.cmake   | 20 ++++-
 build-scripts/build-release.py                | 81 +++++++++++++++++--
 cmake/test/CMakeLists.txt                     |  4 +
 5 files changed, 108 insertions(+), 15 deletions(-)

diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index c82183b80aad8..4a1b6870f7177 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -330,7 +330,17 @@ jobs:
               -B build_x64 -A x64
           cmake --build build_x64 --config Release --verbose
           ctest --test-dir build_x64 --no-tests=error -C Release --output-on-failure
-
+      - name: 'CMake (configure + build + tests) arm64'
+        run: |
+          $env:PATH += ";${{ steps.bin.outputs.path }}/x86"
+          cmake -S "${{ steps.src.outputs.path }}/cmake/test"     `
+              -DTEST_FULL=TRUE                                    `
+              -DTEST_STATIC=FALSE                                 `
+              -DTEST_TEST=TRUE                                    `
+              -DCMAKE_PREFIX_PATH="${{ steps.bin.outputs.path }}" `
+              -Werror=dev                                         `
+              -B build_arm64 -A ARM64
+          cmake --build build_x64 --config Release --verbose
 
   mingw:
     needs: [src]
diff --git a/VisualC/pkg-support/cmake/sdl3-config-version.cmake b/VisualC/pkg-support/cmake/sdl3-config-version.cmake
index fc0d826b17021..f39edf85d474d 100644
--- a/VisualC/pkg-support/cmake/sdl3-config-version.cmake
+++ b/VisualC/pkg-support/cmake/sdl3-config-version.cmake
@@ -47,8 +47,8 @@ if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "")
     set(PACKAGE_VERSION_UNSUITABLE TRUE)
 endif()
 
-# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
-if(NOT (CMAKE_SIZEOF_VOID_P STREQUAL "8" OR CMAKE_SIZEOF_VOID_P STREQUAL "4"))
-    set(PACKAGE_VERSION "${PACKAGE_VERSION} (32+64bit)")
+# check that the installed version has a compatible architecture as the one which is currently searching:
+if(NOT (CMAKE_SYSTEM_PROCESSOR MATCHES "([aA][mM][dD]64|[xX]86((_|-)64)?|[iI][34567]86|[aA][aA][rR][cC][hH]64|[aA][rR][mM]64)"))
+    set(PACKAGE_VERSION "${PACKAGE_VERSION} (x86,x64,arm64)")
     set(PACKAGE_VERSION_UNSUITABLE TRUE)
 endif()
diff --git a/VisualC/pkg-support/cmake/sdl3-config.cmake b/VisualC/pkg-support/cmake/sdl3-config.cmake
index fda40b7de39ec..7bf3bf25f5b3a 100644
--- a/VisualC/pkg-support/cmake/sdl3-config.cmake
+++ b/VisualC/pkg-support/cmake/sdl3-config.cmake
@@ -30,10 +30,22 @@ endmacro()
 
 set(SDL3_FOUND TRUE)
 
-if(CMAKE_SIZEOF_VOID_P STREQUAL "4")
-    set(_sdl_arch_subdir "x86")
-elseif(CMAKE_SIZEOF_VOID_P STREQUAL "8")
-    set(_sdl_arch_subdir "x64")
+if(CMAKE_SYSTEM_PROCESSOR MATCHES "([aA][mM][dD]64|[xX]86(_|-64)?|[iI][34567]86)")
+    if(CMAKE_SIZEOF_VOID_P EQUAL "4")
+        set(_sdl_arch_subdir "x86")
+    elseif(CMAKE_SIZEOF_VOID_P EQUAL "8")
+        set(_sdl_arch_subdir "x64")
+    else()
+        set(SDL3_FOUND FALSE)
+        return()
+    endif()
+elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "([aA][aA][rR][cC][hH]64|[aA][rR][mM]64)")
+    if(CMAKE_SIZEOF_VOID_P EQUAL "8")
+        set(_sdl_arch_subdir "arm64")
+    else()
+        set(SDL3_FOUND FALSE)
+        return()
+    endif()
 else()
     set(SDL3_FOUND FALSE)
     return()
diff --git a/build-scripts/build-release.py b/build-scripts/build-release.py
index 2779d0c4255b2..04d164647b2f2 100755
--- a/build-scripts/build-release.py
+++ b/build-scripts/build-release.py
@@ -409,7 +409,8 @@ def build_vs(self, arch: str, platform: str, vs: VisualStudio, configuration: st
             self.root / "VisualC/SDL_test/SDL_test.vcxproj",
         ]
 
-        vs.build(arch=arch, platform=platform, configuration=configuration, projects=projects)
+        with self.section_printer.group(f"Build {arch} VS binary"):
+            vs.build(arch=arch, platform=platform, configuration=configuration, projects=projects)
 
         if self.dry:
             dll_path.parent.mkdir(parents=True, exist_ok=True)
@@ -437,6 +438,72 @@ def build_vs(self, arch: str, platform: str, vs: VisualStudio, configuration: st
 
         return VcArchDevel(dll=dll_path, pdb=pdb_path, imp=imp_path, test=test_path)
 
+    def build_vs_cmake(self, arch: str, arch_cmake: str):
+        build_path = self.root / f"build-vs-{arch}"
+        install_path = build_path / "prefix"
+        dll_path = install_path / f"bin/{self.project}.dll"
+        pdb_path = install_path / f"bin/{self.project}.pdb"
+        imp_path = install_path / f"lib/{self.project}.lib"
+        test_path = install_path / f"lib/{self.project}_test.lib"
+
+        dll_path.unlink(missing_ok=True)
+        pdb_path.unlink(missing_ok=True)
+        imp_path.unlink(missing_ok=True)
+        test_path.unlink(missing_ok=True)
+
+        build_type = "Release"
+
+        shutil.rmtree(install_path, ignore_errors=True)
+        build_path.mkdir(parents=True, exist_ok=True)
+        with self.section_printer.group(f"Configure VC CMake project for {arch}"):
+            self.executer.run([
+                "cmake", "-S", str(self.root), "-B", str(build_path),
+                "--fresh",
+                "-A", arch_cmake,
+                "-DSDL_SHARED=ON",
+                "-DSDL_STATIC=OFF",
+                "-DSDL_DISABLE_INSTALL_DOCS=ON",
+                "-DSDL_TEST_LIBRARY=ON",
+                "-DSDL_TESTS=OFF",
+                "-DCMAKE_INSTALL_BINDIR=bin",
+                "-DCMAKE_INSTALL_DATAROOTDIR=share",
+                "-DCMAKE_INSTALL_INCLUDEDIR=include",
+                "-DCMAKE_INSTALL_LIBDIR=lib",
+                f"-DCMAKE_BUILD_TYPE={build_type}",
+                f"-DCMAKE_INSTALL_PREFIX={install_path}",
+                # MSVC debug information format flags are selected by an abstraction
+                "-DCMAKE_POLICY_DEFAULT_CMP0141=NEW",
+                # MSVC debug information format
+                "-DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=ProgramDatabase",
+                # Linker flags for executables
+                "-DCMAKE_EXE_LINKER_FLAGS=-DEBUG",
+                # Linker flag for shared libraries
+                "-DCMAKE_SHARED_LINKER_FLAGS=-INCREMENTAL:NO -DEBUG -OPT:REF -OPT:ICF",
+            ])
+
+        with self.section_printer.group(f"Build VC CMake project for {arch}"):
+            self.executer.run(["cmake", "--build", str(build_path), "--verbose", "--config", build_type])
+        with self.section_printer.group(f"Install VC CMake project for {arch}"):
+            self.executer.run(["cmake", "--install", str(build_path), "--config", build_type])
+
+        assert dll_path.is_file(), "SDL3.dll has not been created"
+        assert pdb_path.is_file(), "SDL3.pdb has not been created"
+        assert imp_path.is_file(), "SDL3.lib has not been created"
+        assert test_path.is_file(), "SDL3_test.lib has not been created"
+
+        zip_path = self.dist_path / f"{self.project}-{self.version}-win32-{arch}.zip"
+        zip_path.unlink(missing_ok=True)
+        logger.info("Creating %s", zip_path)
+        with zipfile.ZipFile(zip_path, mode="w", compression=zipfile.ZIP_DEFLATED) as zf:
+            logger.debug("Adding %s", dll_path.name)
+            zf.write(dll_path, arcname=dll_path.name)
+            logger.debug("Adding %s", "README-SDL.txt")
+            zf.write(self.root / "README-SDL.txt", arcname="README-SDL.txt")
+            self._zip_add_git_hash(zip_file=zf)
+        self.artifacts[f"VC-{arch}"] = zip_path
+
+        return VcArchDevel(dll=dll_path, pdb=pdb_path, imp=imp_path, test=test_path)
+
     def build_vs_devel(self, arch_vc: dict[str, VcArchDevel]):
         zip_path = self.dist_path / f"{self.project}-devel-{self.version}-VC.zip"
         archive_prefix = f"{self.project}-{self.version}"
@@ -695,7 +762,7 @@ def main(argv=None):
         logger.warning("%s detected: Building from archive", GIT_HASH_FILENAME)
         archive_commit = root_git_hash_path.read_text().strip()
         if args.commit != archive_commit:
-            logger.warn("Commit argument is %s, but archive commit is %s. Using %s.", args.commit, archive_commit, archive_commit)
+            logger.warning("Commit argument is %s, but archive commit is %s. Using %s.", args.commit, archive_commit, archive_commit)
         args.commit = archive_commit
     else:
         args.commit = executer.run(["git", "rev-parse", args.commit], stdout=True, dry_out="e5812a9fd2cda317b503325a702ba3c1c37861d9").stdout.strip()
@@ -712,7 +779,7 @@ def main(argv=None):
     )
 
     if root_is_maybe_archive:
-        logger.warn("Building from archive. Skipping clean git tree check.")
+        logger.warning("Building from archive. Skipping clean git tree check.")
     else:
         porcelain_status = executer.run(["git", "status", "--ignored", "--porcelain"], stdout=True, dry_out="\n").stdout.strip()
         if porcelain_status:
@@ -750,14 +817,14 @@ def main(argv=None):
             parser.error("win32 artifact(s) can only be built on Windows")
         with section_printer.group("Find Visual Studio"):
             vs = VisualStudio(executer=executer)
-        with section_printer.group("Build x86 VS binary"):
-            x86 = releaser.build_vs(arch="x86", platform="Win32", vs=vs)
-        with section_printer.group("Build x64 VS binary"):
-            x64 = releaser.build_vs(arch="x64", platform="x64", vs=vs)
+        arm64 = releaser.build_vs_cmake(arch="arm64", arch_cmake="ARM64")
+        x86 = releaser.build_vs(arch="x86", platform="Win32", vs=vs)
+        x64 = releaser.build_vs(arch="x64", platform="x64", vs=vs)
         with section_printer.group("Create SDL VC development zip"):
             arch_vc = {
                 "x86": x86,
                 "x64": x64,
+                "arm64": arm64,
             }
             releaser.build_vs_devel(arch_vc)
 
diff --git a/cmake/test/CMakeLists.txt b/cmake/test/CMakeLists.txt
index 9177bdc49c637..f25936d57c272 100644
--- a/cmake/test/CMakeLists.txt
+++ b/cmake/test/CMakeLists.txt
@@ -2,6 +2,10 @@
 
 cmake_minimum_required(VERSION 3.12)
 project(sdl_test LANGUAGES C)
+
+message(STATUS "CMAKE_SYSTEM_NAME=      ${CMAKE_SYSTEM_NAME}")
+message(STATUS "CMAKE_SYSTEM_PROCESSOR= ${CMAKE_SYSTEM_PROCESSOR}")
+
 if(WINDOWS_STORE)
     enable_language(CXX)
     add_compile_options(/ZW)