SDL: ci: merge all workflows (bc8a1)

From bc8a1fd7d5ea160306223c844985d31556ea69e7 Mon Sep 17 00:00:00 2001
From: Anonymous Maarten <[EMAIL REDACTED]>
Date: Sat, 23 Nov 2024 04:03:57 +0100
Subject: [PATCH] ci: merge all workflows

(cherry picked from commit ba433e4a5d9857ff56233d20c688962c23140ef0)
---
 .github/actions/setup-vita-gles/action.yml |  93 +++
 .github/workflows/android.yml              |  81 ---
 .github/workflows/cpactions.yml            |  51 --
 .github/workflows/create-test-plan.py      | 801 +++++++++++++++++++++
 .github/workflows/emscripten.yml           |  45 --
 .github/workflows/generic.yml              | 352 +++++++++
 .github/workflows/ios.yml                  |  20 -
 .github/workflows/msvc.yml                 |  80 --
 .github/workflows/n3ds.yml                 |  55 --
 .github/workflows/ps2.yaml                 |  73 --
 .github/workflows/psp.yaml                 |  50 --
 .github/workflows/riscos.yml               |  68 --
 .github/workflows/vita.yaml                |  95 ---
 .github/workflows/watcom.yml               |  35 -
 test/CMakeLists.txt                        |   4 +-
 15 files changed, 1248 insertions(+), 655 deletions(-)
 create mode 100644 .github/actions/setup-vita-gles/action.yml
 delete mode 100644 .github/workflows/android.yml
 delete mode 100644 .github/workflows/cpactions.yml
 create mode 100755 .github/workflows/create-test-plan.py
 delete mode 100644 .github/workflows/emscripten.yml
 create mode 100644 .github/workflows/generic.yml
 delete mode 100644 .github/workflows/ios.yml
 delete mode 100644 .github/workflows/msvc.yml
 delete mode 100644 .github/workflows/n3ds.yml
 delete mode 100644 .github/workflows/ps2.yaml
 delete mode 100644 .github/workflows/psp.yaml
 delete mode 100644 .github/workflows/riscos.yml
 delete mode 100644 .github/workflows/vita.yaml
 delete mode 100644 .github/workflows/watcom.yml

diff --git a/.github/actions/setup-vita-gles/action.yml b/.github/actions/setup-vita-gles/action.yml
new file mode 100644
index 0000000000000..e263737b31e20
--- /dev/null
+++ b/.github/actions/setup-vita-gles/action.yml
@@ -0,0 +1,93 @@
+name: 'Setup GLES for PlayStation Vita'
+description: 'Download GLES for VITA (PVR or PIB), and copy it into the vita sdk'
+inputs:
+  pib-version:
+    description: 'PIB version'
+    default: '1.1.4'
+  pvr-version:
+    description: 'PVR_PSP2 version'
+    default: '3.9'
+  type:
+    description: '"pib" or "pvr"'
+    default: ''
+runs:
+  using: 'composite'
+  steps:
+    - name: 'Calculate variables'
+      id: calc
+      shell: sh
+      run: |
+        if test "x${VITASDK}" = "x"; then
+          echo "VITASDK must be defined"
+          exit 1;
+        fi
+        case "x${{ inputs.type }}" in
+          "xpvr")
+            echo "cache-key=SDL-vita-gles-pvr-${{ inputs.pvr-version}}" >> ${GITHUB_OUTPUT}
+            ;;
+          "xpib")
+            echo "cache-key=SDL-vita-gles-pib-${{ inputs.pib-version}}" >> ${GITHUB_OUTPUT}
+            ;;
+          *)
+            echo "Invalid type. Must be 'pib' or 'pvr'."
+            exit 1
+            ;;
+        esac
+    - uses: actions/cache/restore@v4
+      id: restore-cache
+      with:
+        path: /vita/dependencies
+        key: '${{ steps.calc.outputs.cache-key }}'
+    - name: 'Download PVR_PSP2 (GLES)'
+      if: ${{ !steps.restore-cache.outputs.cache-hit && inputs.type == 'pvr' }}
+      shell: sh
+      run: |
+        pvr_psp2_version=${{ inputs.pvr-version }}
+        
+        mkdir -p /vita/dependencies/include
+        mkdir -p /vita/dependencies/lib
+        
+        # Configure PVR_PSP2 headers
+        wget https://github.com/GrapheneCt/PVR_PSP2/archive/refs/tags/v$pvr_psp2_version.zip -P/tmp
+        unzip /tmp/v$pvr_psp2_version.zip -d/tmp
+        cp -r /tmp/PVR_PSP2-$pvr_psp2_version/include/* /vita/dependencies/include
+        rm /tmp/v$pvr_psp2_version.zip
+        
+        # include guard of PVR_PSP2's khrplatform.h does not match the usual one
+        sed -i -e s/__drvkhrplatform_h_/__khrplatform_h_/ /vita/dependencies/include/KHR/khrplatform.h
+        
+        # Configure PVR_PSP2 stub libraries
+        wget https://github.com/GrapheneCt/PVR_PSP2/releases/download/v$pvr_psp2_version/vitasdk_stubs.zip -P/tmp
+        unzip /tmp/vitasdk_stubs.zip -d/tmp/pvr_psp2_stubs
+        find /tmp/pvr_psp2_stubs -type f -name "*.a" -exec cp {} /vita/dependencies/lib \;
+        rm /tmp/vitasdk_stubs.zip
+        rm -rf /tmp/pvr_psp2_stubs
+
+    - name: 'Download gl4es4vita (OpenGL)'
+      if: ${{ !steps.restore-cache.outputs.cache-hit && inputs.type == 'pib' }}
+      shell: sh
+      run: |
+        gl4es4vita_version=${{ inputs.pib-version }}
+        
+        mkdir -p /vita/dependencies/include
+        mkdir -p /vita/dependencies/lib
+        
+        # Configure gl4es4vita headers
+        wget https://github.com/SonicMastr/gl4es4vita/releases/download/v$gl4es4vita_version-vita/include.zip -P/tmp
+        unzip -o /tmp/include.zip -d/vita/dependencies/include
+        rm /tmp/include.zip
+        
+        # Configure gl4es4vita stub libraries
+        wget https://github.com/SonicMastr/gl4es4vita/releases/download/v$gl4es4vita_version-vita/vitasdk_stubs.zip -P/tmp
+        unzip /tmp/vitasdk_stubs.zip -d/vita/dependencies/lib
+
+    - uses: actions/cache/save@v4
+      if: ${{ !steps.restore-cache.outputs.cache-hit }}
+      with:
+        path: /vita/dependencies
+        key: '${{ steps.calc.outputs.cache-key }}'
+
+    - name: Copy PVR_PSP2 (GLES) or gl4es4vita (OpenGL) to vita toolchain dir
+      shell: sh
+      run: |
+        cp -rv /vita/dependencies/* ${VITASDK}/arm-vita-eabi
diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
deleted file mode 100644
index a2d2b0b50592b..0000000000000
--- a/.github/workflows/android.yml
+++ /dev/null
@@ -1,81 +0,0 @@
-name: Build (Android)
-
-on: [push, pull_request]
-
-jobs:
-  android:
-    name: ${{ matrix.platform.name }}
-    runs-on: ubuntu-latest
-
-    strategy:
-      fail-fast: false
-      matrix:
-        platform:
-          - { name: Android.mk  }
-          - { name: CMake, cmake: 1, android_abi: "arm64-v8a", android_platform: 23, arch: "aarch64" }
-
-    steps:
-      - uses: actions/checkout@v4
-      - uses: nttld/setup-ndk@v1
-        id: setup_ndk
-        with:
-          ndk-version: r21e
-      - name: Build (Android.mk)
-        if: ${{ matrix.platform.name == 'Android.mk' }}
-        run: |
-          ./build-scripts/androidbuildlibs.sh
-      - name: Setup (CMake)
-        if: ${{ matrix.platform.name == 'CMake' }}
-        run: |
-          sudo apt-get update
-          sudo apt-get install ninja-build pkg-config
-      - name: Configure (CMake)
-        if: ${{ matrix.platform.name == 'CMake' }}
-        run: |
-          cmake -B build \
-            -DCMAKE_TOOLCHAIN_FILE=${{ steps.setup_ndk.outputs.ndk-path }}/build/cmake/android.toolchain.cmake \
-            -DSDL_WERROR=ON \
-            -DANDROID_PLATFORM=${{ matrix.platform.android_platform }} \
-            -DANDROID_ABI=${{ matrix.platform.android_abi }} \
-            -DSDL_STATIC_PIC=ON \
-            -DSDL_VENDOR_INFO="Github Workflow" \
-            -DCMAKE_INSTALL_PREFIX=prefix \
-            -DCMAKE_BUILD_TYPE=Release \
-            -GNinja
-      - name: Build (CMake)
-        if: ${{ matrix.platform.name == 'CMake' }}
-        run: |
-          cmake --build build --config Release --parallel --verbose
-      - name: Install (CMake)
-        if: ${{ matrix.platform.name == 'CMake' }}
-        run: |
-          cmake --install build --config Release
-          echo "SDL2_DIR=$(pwd)/prefix" >> $GITHUB_ENV
-          ( cd prefix; find ) | LC_ALL=C sort -u
-      - name: Verify CMake configuration files
-        if: ${{ matrix.platform.name == 'CMake' }}
-        run: |
-          cmake -S cmake/test -B cmake_config_build -G Ninja \
-            -DCMAKE_TOOLCHAIN_FILE=${{ steps.setup_ndk.outputs.ndk-path }}/build/cmake/android.toolchain.cmake \
-            -DANDROID_PLATFORM=${{ matrix.platform.android_platform }} \
-            -DANDROID_ABI=${{ matrix.platform.android_abi }} \
-            -DCMAKE_BUILD_TYPE=Release \
-            -DCMAKE_PREFIX_PATH=${{ env.SDL2_DIR }}
-          cmake --build cmake_config_build --verbose
-      - name: Verify sdl2-config
-        if: ${{ matrix.platform.name == 'CMake' }}
-        run: |
-          export CC="${{ steps.setup_ndk.outputs.ndk-path }}/toolchains/llvm/prebuilt/linux-x86_64/bin/clang --target=${{ matrix.platform.arch }}-none-linux-androideabi${{ matrix.platform.android_platform }}"
-          export PATH=${{ env.SDL2_DIR }}/bin:$PATH
-          cmake/test/test_sdlconfig.sh
-      - name: Verify sdl2.pc
-        if: ${{ matrix.platform.name == 'CMake' }}
-        run: |
-          export CC="${{ steps.setup_ndk.outputs.ndk-path }}/toolchains/llvm/prebuilt/linux-x86_64/bin/clang --target=${{ matrix.platform.arch }}-none-linux-androideabi${{ matrix.platform.android_platform }}"
-          export PKG_CONFIG_PATH=${{ env.SDL2_DIR }}/lib/pkgconfig
-          cmake/test/test_pkgconfig.sh
-      - name: Verify Android.mk
-        if: ${{ matrix.platform.name == 'CMake' }}
-        run: |
-          export NDK_MODULE_PATH=${{ env.SDL2_DIR }}/share/ndk-modules
-          ndk-build -C ${{ github.workspace }}/cmake/test APP_PLATFORM=android-${{ matrix.platform.android_platform }} APP_ABI=${{ matrix.platform.android_abi }} NDK_OUT=$PWD NDK_LIBS_OUT=$PWD V=1
diff --git a/.github/workflows/cpactions.yml b/.github/workflows/cpactions.yml
deleted file mode 100644
index acd40a930b44a..0000000000000
--- a/.github/workflows/cpactions.yml
+++ /dev/null
@@ -1,51 +0,0 @@
-name: Build (C/P Actions)
-
-on: [push, pull_request]
-
-jobs:
-  freebsd:
-    runs-on: ubuntu-latest
-    name: FreeBSD
-    timeout-minutes: 30
-    steps:
-    - uses: actions/checkout@v4
-    - name: Build
-      uses: cross-platform-actions/action@v0.24.0
-      with:
-        operating_system: freebsd
-        version: '13.3'
-        shell: bash
-        run: |
-          sudo pkg update
-          sudo pkg install -y \
-              gmake \
-              pkgconf \
-              libXcursor \
-              libXext \
-              libXinerama \
-              libXi \
-              libXfixes \
-              libXrandr \
-              libXScrnSaver \
-              libXxf86vm \
-              wayland \
-              wayland-protocols \
-              libxkbcommon \
-              mesa-libs \
-              libglvnd \
-              evdev-proto \
-              libinotify \
-              alsa-lib \
-              jackit \
-              pipewire \
-              pulseaudio \
-              sndio \
-              dbus \
-              zh-fcitx \
-              ibus \
-              libudev-devd
-          mkdir build_autotools
-          export CPPFLAGS="-I/usr/local/include"
-          export LDFLAGS="-L/usr/local/lib"
-          (cd build_autotools && ../configure --disable-static)
-          gmake -C build_autotools -j`sysctl -n hw.ncpu` V=1
diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py
new file mode 100755
index 0000000000000..f7cb9401a3182
--- /dev/null
+++ b/.github/workflows/create-test-plan.py
@@ -0,0 +1,801 @@
+#!/usr/bin/env python
+import argparse
+import dataclasses
+import fnmatch
+from enum import Enum
+import json
+import logging
+import os
+import re
+from typing import Optional
+
+logger = logging.getLogger(__name__)
+
+
+class AppleArch(Enum):
+    ARM64 = "arm64"
+    X86_64 = "x86_64"
+
+
+class MsvcArch(Enum):
+    X86 = "x86"
+    X64 = "x64"
+    Arm32 = "arm"
+    Arm64 = "arm64"
+
+
+class JobOs(Enum):
+    WindowsLatest = "windows-latest"
+    UbuntuLatest = "ubuntu-latest"
+    MacosLatest = "macos-latest"
+    Ubuntu20_04 = "ubuntu-20.04"
+    Ubuntu22_04 = "ubuntu-22.04"
+    Ubuntu24_04 = "ubuntu-24.04"
+    Macos13 = "macos-13"
+
+
+class SdlPlatform(Enum):
+    Android = "android"
+    Emscripten = "emscripten"
+    Haiku = "haiku"
+    Msys2 = "msys2"
+    Linux = "linux"
+    MacOS = "macos"
+    Ios = "ios"
+    Tvos = "tvos"
+    Msvc = "msvc"
+    N3ds = "n3ds"
+    Ps2 = "ps2"
+    Psp = "psp"
+    Vita = "vita"
+    Riscos = "riscos"
+    FreeBSD = "freebsd"
+    NetBSD = "netbsd"
+    Watcom = "watcom"
+
+
+class Msys2Platform(Enum):
+    Mingw32 = "mingw32"
+    Mingw64 = "mingw64"
+    Clang32 = "clang32"
+    Clang64 = "clang64"
+    Ucrt64 = "ucrt64"
+
+
+class IntelCompiler(Enum):
+    Icc = "icc"
+    Icx = "icx"
+
+
+class VitaGLES(Enum):
+    Pib = "pib"
+    Pvr = "pvr"
+
+class WatcomPlatform(Enum):
+    Windows = "windows"
+    OS2 = "OS/2"
+
+
+@dataclasses.dataclass(slots=True)
+class JobSpec:
+    name: str
+    os: JobOs
+    platform: SdlPlatform
+    artifact: Optional[str]
+    container: Optional[str] = None
+    autotools: bool = False
+    no_cmake: bool = False
+    xcode: bool = False
+    android_mk: bool = False
+    lean: bool = False
+    android_arch: Optional[str] = None
+    android_abi: Optional[str] = None
+    android_platform: Optional[int] = None
+    msys2_platform: Optional[Msys2Platform] = None
+    intel: Optional[IntelCompiler] = None
+    apple_archs: Optional[set[AppleArch]] = None
+    msvc_project: Optional[str] = None
+    msvc_arch: Optional[MsvcArch] = None
+    msvc_static_crt: bool = False
+    clang_cl: bool = False
+    gdk: bool = False
+    uwp: bool = False
+    vita_gles: Optional[VitaGLES] = None
+    watcom_platform: Optional[WatcomPlatform] = None
+
+
+JOB_SPECS = {
+    "msys2-mingw32": JobSpec(name="Windows (msys2, mingw32)",               os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2,       artifact="SDL-mingw32",            msys2_platform=Msys2Platform.Mingw32, ),
+    "msys2-mingw64": JobSpec(name="Windows (msys2, mingw64)",               os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2,       artifact="SDL-mingw64",            msys2_platform=Msys2Platform.Mingw64, ),
+    "msys2-clang32": JobSpec(name="Windows (msys2, clang32)",               os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2,       artifact="SDL-mingw32-clang",      msys2_platform=Msys2Platform.Clang32, ),
+    "msys2-clang64": JobSpec(name="Windows (msys2, clang64)",               os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2,       artifact="SDL-mingw64-clang",      msys2_platform=Msys2Platform.Clang64, ),
+    "msys2-ucrt64": JobSpec(name="Windows (msys2, ucrt64)",                 os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2,       artifact="SDL-mingw64-ucrt",       msys2_platform=Msys2Platform.Ucrt64, ),
+    "msvc-x64": JobSpec(name="Windows (MSVC, x64)",                         os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc,        artifact="SDL-VC-x64",             msvc_arch=MsvcArch.X64,   msvc_project="VisualC/SDL.sln", ),
+    "msvc-x86": JobSpec(name="Windows (MSVC, x86)",                         os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc,        artifact="SDL-VC-x86",             msvc_arch=MsvcArch.X86,   msvc_project="VisualC/SDL.sln", ),
+    "msvc-static-x86": JobSpec(name="Windows (MSVC, static VCRT, x86)",     os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc,        artifact="SDL-VC-x86",             msvc_arch=MsvcArch.X86,   msvc_static_crt=True, ),
+    "msvc-static-x64": JobSpec(name="Windows (MSVC, static VCRT, x64)",     os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc,        artifact="SDL-VC-x64",             msvc_arch=MsvcArch.X64,   msvc_static_crt=True, ),
+    "msvc-clang-x64": JobSpec(name="Windows (MSVC, clang-cl x64)",          os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc,        artifact="SDL-clang-cl-x64",       msvc_arch=MsvcArch.X64,   clang_cl=True, ),
+    "msvc-clang-x86": JobSpec(name="Windows (MSVC, clang-cl x86)",          os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc,        artifact="SDL-clang-cl-x86",       msvc_arch=MsvcArch.X86,   clang_cl=True, ),
+    "msvc-arm32": JobSpec(name="Windows (MSVC, ARM)",                       os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc,        artifact="SDL-VC-arm32",           msvc_arch=MsvcArch.Arm32, ),
+    "msvc-arm64": JobSpec(name="Windows (MSVC, ARM64)",                     os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc,        artifact="SDL-VC-arm64",           msvc_arch=MsvcArch.Arm64, ),
+    "msvc-uwp-x64": JobSpec(name="UWP (MSVC, x64)",                         os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc,        artifact="SDL-VC-UWP",             msvc_arch=MsvcArch.X64,   msvc_project="VisualC-WinRT/SDL-UWP.sln", uwp=True, ),
+    "msvc-gdk-x64": JobSpec(name="GDK (MSVC, x64)",                         os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc,        artifact="SDL-VC-GDK",             msvc_arch=MsvcArch.X64,   msvc_project="VisualC-GDK/SDL.sln", gdk=True, no_cmake=True, ),
+    "ubuntu-20.04": JobSpec(name="Ubuntu 20.04",                            os=JobOs.Ubuntu20_04,   platform=SdlPlatform.Linux,       artifact="SDL-ubuntu20.04",        autotools=True),
+    "ubuntu-22.04": JobSpec(name="Ubuntu 22.04",                            os=JobOs.Ubuntu22_04,   platform=SdlPlatform.Linux,       artifact="SDL-ubuntu22.04",        autotools=True),
+    "steamrt-sniper": JobSpec(name="Steam Linux Runtime (Sniper)",          os=JobOs.UbuntuLatest,  platform=SdlPlatform.Linux,       artifact="SDL-slrsniper",          container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk:beta", ),
+    "ubuntu-intel-icx": JobSpec(name="Ubuntu 20.04 (Intel oneAPI)",         os=JobOs.Ubuntu20_04,   platform=SdlPlatform.Linux,       artifact="SDL-ubuntu20.04-oneapi", intel=IntelCompiler.Icx, ),
+    "ubuntu-intel-icc": JobSpec(name="Ubuntu 20.04 (Intel Compiler)",       os=JobOs.Ubuntu20_04,   platform=SdlPlatform.Linux,       artifact="SDL-ubuntu20.04-icc",    intel=IntelCompiler.Icc, ),
+    "macos-gnu-arm64-x64": JobSpec(name="MacOS (GNU prefix)",               os=JobOs.MacosLatest,   platform=SdlPlatform.MacOS,       artifact="SDL-macos-arm64-x64-gnu",autotools=True, apple_archs={AppleArch.X86_64, AppleArch.ARM64, },  ),
+    "ios": JobSpec(name="iOS (CMake & xcode)",                              os=JobOs.MacosLatest,   platform=SdlPlatform.Ios,         artifact="SDL-ios-arm64",          xcode=True, ),
+    "tvos": JobSpec(name="tvOS (CMake & xcode)",                            os=JobOs.MacosLatest,   platform=SdlPlatform.Tvos,        artifact="SDL-tvos-arm64",         xcode=True, ),
+    "android-cmake": JobSpec(name="Android (CMake)",                        os=JobOs.UbuntuLatest,  platform=SdlPlatform.Android,     artifact="SDL-android-arm64",      android_abi="arm64-v8a", android_arch="aarch64", android_platform=23, ),
+    "android-mk": JobSpec(name="Android (Android.mk)",                      os=JobOs.UbuntuLatest,  platform=SdlPlatform.Android,     artifact=None,                     no_cmake=True, android_mk=True, ),
+    "emscripten": JobSpec(name="Emscripten",                                os=JobOs.UbuntuLatest,  platform=SdlPlatform.Emscripten,  artifact="SDL-emscripten", ),
+    "haiku": JobSpec(name="Haiku",                                          os=JobOs.UbuntuLatest,  platform=SdlPlatform.Haiku,       artifact="SDL-haiku-x64",          container="ghcr.io/haiku/cross-compiler:x86_64-r1beta5", ),
+    "n3ds": JobSpec(name="Nintendo 3DS",                                    os=JobOs.UbuntuLatest,  platform=SdlPlatform.N3ds,        artifact="SDL-n3ds",               container="devkitpro/devkitarm:latest", ),
+    "ps2": JobSpec(name="Sony PlayStation 2",                               os=JobOs.UbuntuLatest,  platform=SdlPlatform.Ps2,         artifact="SDL-ps2",                container="ps2dev/ps2dev:latest", ),
+    "psp": JobSpec(name="Sony PlayStation Portable",                        os=JobOs.UbuntuLatest,  platform=SdlPlatform.Psp,         artifact="SDL-psp",                container="pspdev/pspdev:latest", ),
+    "vita-pib": JobSpec(name="Sony PlayStation Vita (GLES w/ pib)",         os=JobOs.UbuntuLatest,  platform=SdlPlatform.Vita,        artifact="SDL-vita-pib",           container="vitasdk/vitasdk:latest", vita_gles=VitaGLES.Pib,  ),
+    "vita-pvr": JobSpec(name="Sony PlayStation Vita (GLES w/ PVR_PSP2)",    os=JobOs.UbuntuLatest,  platform=SdlPlatform.Vita,        artifact="SDL-vita-pvr",           container="vitasdk/vitasdk:latest", vita_gles=VitaGLES.Pvr, ),
+    "riscos": JobSpec(name="RISC OS",                                       os=JobOs.UbuntuLatest,  platform=SdlPlatform.Riscos,      artifact="SDL-riscos",             container="riscosdotinfo/riscos-gccsdk-4.7:latest", ),
+    "netbsd": JobSpec(name="NetBSD",                                        os=JobOs.UbuntuLatest,  platform=SdlPlatform.NetBSD,      artifact="SDL-netbsd-x64",  autotools=True, ),
+    "freebsd": JobSpec(name="FreeBSD",                                      os=JobOs.UbuntuLatest,  platform=SdlPlatform.FreeBSD,     artifact="SDL-freebsd-x64", autotools=True, ),
+    "watcom-win32": JobSpec(name="Watcom (Windows)",                        os=JobOs.WindowsLatest, platform=SdlPlatform.Watcom,      artifact="SDL-watcom-win32",  no_cmake=True, watcom_platform=WatcomPlatform.Windows ),
+    "watcom-os2": JobSpec(name="Watcom (OS/2)",                             os=JobOs.WindowsLatest, platform=SdlPlatform.Watcom,      artifact="SDL-watcom-win32",  no_cmake=True, watcom_platform=WatcomPlatform.OS2 ),
+    # "watcom-win32"
+    # "watcom-os2"
+}
+
+
+class StaticLibType(Enum):
+    MSVC = "SDL2-static.lib"
+    A = "libSDL2.a"
+
+
+class SharedLibType(Enum):
+    WIN32 = "SDL2.dll"
+    SO_0 = "libSDL2-2.0.so.0"
+    SO = "libSDL2.so"
+    DYLIB = "libSDL2-2.0.0.dylib"
+    FRAMEWORK = "SDL2.framework/Versions/A/SDL2"
+
+
+@dataclasses.dataclass(slots=True)
+class JobDetails:
+    name: str
+    key: str
+    os: str
+    platform: str
+    artifact: str
+    no_autotools: bool
+    no_cmake: bool
+    build_autotools_tests: bool = True
+    build_tests: bool = True
+    container: str = ""
+    cmake_build_type: str = "RelWithDebInfo"
+    shell: str = "sh"
+    sudo: str = "sudo"
+    cmake_config_emulator: str = ""
+    apk_packages: list[str] = dataclasses.field(default_factory=list)
+    apt_packages: list[str] = dataclasses.field(default_factory=list)
+    brew_packages: list[str] = dataclasses.field(default_factory=list)
+    cmake_toolchain_file: str = ""
+    cmake_arguments: list[str] = dataclasses.field(default_factory=list)
+    cmake_build_arguments: list[str] = dataclasses.field(default_factory=list)
+    cppflags: list[str] = dataclasses.field(default_factory=list)
+    cc: str = ""
+    cxx: str = ""
+    cflags: list[str] = dataclasses.field(default_factory=list)
+    cxxflags: list[str] = dataclasses.field(default_factory=list)
+    ldflags: list[str] = dataclasses.field(default_factory=list)
+    pollute_directories: list[str] = dataclasses.field(default_factory=list)
+    use_cmake: bool = True
+    shared: bool = True
+    static: bool = True
+    shared_lib: Optional[SharedLibType] = None
+    static_lib: Optional[StaticLibType] = None
+    run_tests: bool = True
+    test_pkg_config: bool = True
+    cc_from_cmake: bool = False
+    source_cmd: str = ""
+    pretest_cmd: str = ""
+    android_apks: list[str] = dataclasses.field(default_factory=list)
+    android_ndk: bool = False
+    android_mk: bool = False
+    minidump: bool = False
+    intel: bool = False
+    msys2_msystem: str = ""
+    msys2_env: str = ""
+    msys2_no_perl: bool = False
+    werror: bool = True
+    msvc_vcvars_arch: str = ""
+    msvc_vcvars_sdk: str = ""
+    msvc_project: str = ""
+    msvc_project_flags: list[str] = dataclasses.field(default_factory=list)
+    setup_ninja: bool = False
+    setup_libusb_arch: str = ""
+    xcode_sdk: str = ""
+    xcode_target: str = ""
+    setup_gdk_folder: str = ""
+    cpactions: bool = False
+    cpactions_os: str = ""
+    cpactions_version: str = ""
+    cpactions_arch: str = ""
+    cpactions_setup_cmd: str = ""
+    cpactions_install_cmd: str = ""
+    setup_vita_gles_type: str = ""
+    check_sources: bool = False
+    watcom_makefile: str = ""
+
+    def to_workflow(self, enable_artifacts: bool) -> dict[str, str|bool]:
+        data = {
+            "name": self.name,
+            "key": self.key,
+            "os": self.os,
+            "container": self.container if self.container else "",
+            "platform": self.platform,
+            "artifact": self.artifact,
+            "enable-artifacts": enable_artifacts,
+            "shell": self.shell,
+            "msys2-msystem": self.msys2_msystem,
+            "msys2-env": self.msys2_env,
+            "msys2-no-perl": self.msys2_no_perl,
+            "android-ndk": self.android_ndk,
+            "intel": self.intel,
+            "apk-packages": my_shlex_join(self.apk_packages),
+            "apt-packages": my_shlex_join(self.apt_packages),
+            "test-pkg-config": self.test_pkg_config,
+            "brew-packages": my_shlex_join(self.brew_packages),
+            "pollute-directories": my_shlex_join(self.pollute_directories),
+            "no-autotools": self.no_autotools,
+            "no-cmake": self.no_cmake,
+            "build-autotools-tests": self.build_autotools_tests,
+            "build-tests": self.build_tests,
+            "source-cmd": self.source_cmd,
+            "pretest-cmd": self.pretest_cmd,
+            "cmake-config-emulator": self.cmake_config_emulator,
+            "cc": self.cc,
+            "cxx": self.cxx,
+            "cflags": my_shlex_join(self.cppflags + self.cflags),
+            "cxxflags": my_shlex_join(self.cppflags + self.cxxflags),
+            "ldflags": my_shlex_join(self.ldflags),
+            "cmake-toolchain-file": self.cmake_toolchain_file,
+            "cmake-arguments": my_shlex_join(self.cmake_arguments),
+            "cmake-build-arguments": my_shlex_join(self.cmake_build_arguments),
+            "shared": self.shared,
+            "static": self.static,
+            "shared-lib": self.shared_lib.value if self.shared_lib else None,
+            "static-lib": self.static_lib.value if self.static_lib else None,
+            "cmake-build-type": self.cmake_build_type,
+            "run-tests": self.run_tests,
+            "android-apks": my_shlex_join(self.android_apks),
+            "android-mk": self.android_mk,
+            "werror": self.werror,
+            "sudo": self.sudo,
+            "msvc-vcvars-arch": self.msvc_vcvars_arch,
+            "msvc-vcvars-sdk": self.msvc_vcvars_sdk,
+            "msvc-project": self.msvc_project,
+            "msvc-project-flags": my_shlex_join(self.msvc_project_flags),
+            "setup-ninja": self.setup_ninja,
+            "setup-libusb-arch": self.setup_libusb_arch,
+            "cc-from-cmake": self.cc_from_cmake,
+            "xcode-sdk": self.xcode_sdk,
+            "xcode-target": self.xcode_target,
+            "cpactions": self.cpactions,
+            "cpactions-os": self.cpactions_os,
+            "cpactions-version": self.cpactions_version,
+            "cpactions-arch": self.cpactions_arch,
+            "cpactions-setup-cmd": self.cpactions_setup_cmd,
+            "cpactions-install-cmd": self.cpactions_install_cmd,
+            "setup-vita-gles-type": self.setup_vita_gles_type,
+            "setup-gdk-folder": self.setup_gdk_folder,
+            "check-sources": self.check_sources,
+            "watcom-makefile": self.watcom_makefile,
+        }
+        return {k: v for k, v in data.items() if v != ""}
+
+
+def my_shlex_join(s):
+    def escape(s):
+        if s[:1] == "'" and s[-1:] == "'":
+            return s
+        if set(s).intersection(set("; \t")):
+            s = s.replace("\\", "\\\\").replace("\"", "\\\"")
+            return f'"{s}"'
+        return s
+
+    return " ".join(escape(e) for e in s)
+
+
+def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDetails:
+    job = JobDetails(
+        name=spec.name,
+        key=key,
+        os=spec.os.value,
+        artifact=spec.artifact or "",
+        container=spec.container or "",
+        platform=spec.platform.value,
+        sudo="sudo",
+        no_autotools=not spec.autotools,
+        no_cmake=spec.no_cmake,
+    )
+    if job.os.startswith("ubuntu"):
+        job.apt_packages.extend([
+            "ninja-build",
+            "pkg-config",
+        ])
+    if spec.msvc_static_crt:
+        job.cmake_arguments.append("-DSDL_FORCE_STATIC_VCRT=ON")
+    pretest_cmd = []
+    if trackmem_symbol_names:
+        pretest_cmd.append("export SDL_TRACKMEM_SYMBOL_NAMES=1")
+    else:
+        pretest_cmd.append("export SDL_TRACKMEM_SYMBOL_NAMES=0")
+    win32 = spec.platform in (SdlPlatform.Msys2, SdlPlatform.Msvc)
+    fpic = None
+    build_parallel = True
+    if spec.lean:
+        job.cppflags.append("-DSDL_LEAN_AND_MEAN=1")
+    if win32:
+        job.cmake_arguments.append("-DSDLTEST_PROCDUMP=ON")
+        job.minidump = True
+    if spec.intel is not None:
+        match spec.intel:
+            case IntelCompiler.Icx:
+                job.cc = "icx"
+                job.cxx = "icpx"
+            case IntelCompiler.Icc:
+                job.cc = "icc"
+                job.cxx = "icpc"
+                job.cppflags.append("-diag-disable=10441")
+            case _:
+                raise ValueError(f"Invalid intel={spec.intel}")
+        job.source_cmd = f"source /opt/intel/oneapi/setvars.sh;"
+        job.intel = True
+        job.shell = "bash"
+        job.cmake_arguments.extend((
+            f"-DCMAKE_C_COMPILER={job.cc}",
+            f"-DCMAKE_CXX_COMPILER={job.cxx}",
+            "-DCMAKE_SYSTEM_NAME=Linux",
+        ))
+    match spec.platform:
+        case SdlPlatform.Msvc:
+            job.setup_ninja = not spec.gdk
+            job.msvc_project = spec.msvc_project if spec.msvc_project else ""
+            job.msvc_project_flags.append("-p:TreatWarningsAsError=true")
+            job.test_pkg_config = False
+            job.shared_lib = SharedLibType.WIN32
+            job.static_lib = StaticLibType.MSVC
+            job.cmake_arguments.extend((
+                "-DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=ProgramDatabase",
+                "-DCMAKE_EXE_LINKER_FLAGS=-DEBUG",
+                "-DCMAKE_SHARED_LINKER_FLAGS=-DEBUG",
+            ))
+            if spec.uwp:
+                job.cmake_arguments.append("'-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded$<$<CONFIG:Debug>:Debug>DLL'")
+            else:
+                job.cmake_arguments.append("'-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded$<$<CONFIG:Debug>:Debug>'")
+
+            if spec.clang_cl:
+                job.cmake_arguments.extend((
+                    "-DCMAKE_C_COMPILER=clang-cl",
+                    "-DCMAKE_CXX_COMPILER=clang-cl",
+                ))
+                match spec.msvc_arch:
+                    case MsvcArch.X86:
+                        job.cflags.append("/clang:-m32")
+                        job.ldflags.append("/MACHINE:X86")
+                    case MsvcArch.X64:
+                        job.cflags.append("/clang:-m64")
+                        job.ldflags.append("/MACHINE:X64")
+                    case _:
+                        raise ValueError(f"Unsupported clang-cl architecture (arch={spec.msvc_arch})")
+            if spec.msvc_project:
+                match spec.msvc_arch:
+                    case MsvcArch.X86:
+                        msvc_platform = "Win32"
+                    case MsvcArch.X64:
+                        msvc_platform = "x64"
+                    case _:
+                        raise ValueError(f"Unsupported vcxproj architecture (arch={spec.msvc_arch})")
+   

(Patch may be truncated, please check the link at the top of this post.)