create-test-plan.py 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  1. #!/usr/bin/env python
  2. import argparse
  3. import dataclasses
  4. import fnmatch
  5. from enum import Enum
  6. import json
  7. import logging
  8. import os
  9. import pathlib
  10. import re
  11. import shlex
  12. from typing import Optional
  13. logger = logging.getLogger(__name__)
  14. class AppleArch(Enum):
  15. Aarch64 = "aarch64"
  16. X86_64 = "x86_64"
  17. class MsvcArch(Enum):
  18. X86 = "x86"
  19. X64 = "x64"
  20. Arm64 = "arm64"
  21. class JobOs(Enum):
  22. WindowsLatest = "windows-latest"
  23. Windows2022 = "windows-2022"
  24. UbuntuLatest = "ubuntu-latest"
  25. MacosLatest = "macos-latest"
  26. Ubuntu22_04 = "ubuntu-22.04"
  27. Ubuntu24_04 = "ubuntu-24.04"
  28. Ubuntu24_04_arm = "ubuntu-24.04-arm"
  29. Macos14 = "macos-14" # macOS Sonoma (2023)
  30. Macos15 = "macos-15" # macOS Sequoia (2024)
  31. Macos26 = "macos-26" # macOS Tahoe (2025)
  32. class SdlPlatform(Enum):
  33. Android = "android"
  34. Emscripten = "emscripten"
  35. Haiku = "haiku"
  36. LoongArch64 = "loongarch64"
  37. Msys2 = "msys2"
  38. Cygwin = "cygwin"
  39. Linux = "linux"
  40. MacOS = "macos"
  41. Ios = "ios"
  42. Tvos = "tvos"
  43. Msvc = "msvc"
  44. N3ds = "n3ds"
  45. PowerPC = "powerpc"
  46. PowerPC64 = "powerpc64"
  47. Ps2 = "ps2"
  48. Psp = "psp"
  49. Vita = "vita"
  50. Riscos = "riscos"
  51. FreeBSD = "freebsd"
  52. NetBSD = "netbsd"
  53. OpenBSD = "openbsd"
  54. NGage = "ngage"
  55. DJGPP = "djgpp"
  56. class Msys2Platform(Enum):
  57. Mingw32 = "mingw32"
  58. Mingw64 = "mingw64"
  59. Clang64 = "clang64"
  60. Ucrt64 = "ucrt64"
  61. class IntelCompiler(Enum):
  62. Icc = "icc"
  63. Icx = "icx"
  64. class VitaGLES(Enum):
  65. Pib = "pib"
  66. Pvr = "pvr"
  67. @dataclasses.dataclass(slots=True)
  68. class JobSpec:
  69. name: str
  70. priority: bool
  71. os: JobOs
  72. platform: SdlPlatform
  73. artifact: Optional[str]
  74. container: Optional[str] = None
  75. no_cmake: bool = False
  76. xcode: bool = False
  77. android_mk: bool = False
  78. android_gradle: bool = False
  79. lean: bool = False
  80. android_arch: Optional[str] = None
  81. android_abi: Optional[str] = None
  82. android_platform: Optional[int] = None
  83. msys2_platform: Optional[Msys2Platform] = None
  84. intel: Optional[IntelCompiler] = None
  85. apple_framework: Optional[bool] = None
  86. apple_archs: Optional[set[AppleArch]] = None
  87. msvc_project: Optional[str] = None
  88. msvc_arch: Optional[MsvcArch] = None
  89. clang_cl: bool = False
  90. gdk: bool = False
  91. vita_gles: Optional[VitaGLES] = None
  92. more_hard_deps: bool = False
  93. JOB_SPECS = {
  94. "msys2-mingw32": JobSpec(name="Windows (msys2, mingw32)", priority=False, os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw32", msys2_platform=Msys2Platform.Mingw32, ),
  95. "msys2-mingw64": JobSpec(name="Windows (msys2, mingw64)", priority=False, os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64", msys2_platform=Msys2Platform.Mingw64, ),
  96. "msys2-clang64": JobSpec(name="Windows (msys2, clang64)", priority=False, os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64-clang", msys2_platform=Msys2Platform.Clang64, ),
  97. "msys2-ucrt64": JobSpec(name="Windows (msys2, ucrt64)", priority=False, os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64-ucrt", msys2_platform=Msys2Platform.Ucrt64, ),
  98. "cygwin": JobSpec(name="Cygwin", priority=False, os=JobOs.WindowsLatest, platform=SdlPlatform.Cygwin, artifact="SDL-cygwin", ),
  99. "msvc-x64": JobSpec(name="Windows (MSVC, x64)", priority=True, os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-x64", msvc_arch=MsvcArch.X64, msvc_project="VisualC/SDL.sln", ),
  100. "msvc-x86": JobSpec(name="Windows (MSVC, x86)", priority=True, os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-x86", msvc_arch=MsvcArch.X86, msvc_project="VisualC/SDL.sln", ),
  101. "msvc-clang-x64": JobSpec(name="Windows (MSVC, clang-cl x64)", priority=False, os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-clang-cl-x64", msvc_arch=MsvcArch.X64, clang_cl=True, ),
  102. "msvc-clang-x86": JobSpec(name="Windows (MSVC, clang-cl x86)", priority=False, os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-clang-cl-x86", msvc_arch=MsvcArch.X86, clang_cl=True, ),
  103. "msvc-arm64": JobSpec(name="Windows (MSVC, ARM64)", priority=False, os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-arm64", msvc_arch=MsvcArch.Arm64, msvc_project="VisualC/SDL.sln", ),
  104. "msvc-gdk-x64": JobSpec(name="GDK (MSVC, x64)", priority=False, os=JobOs.Windows2022, platform=SdlPlatform.Msvc, artifact="SDL-VC-GDK", msvc_arch=MsvcArch.X64, msvc_project="VisualC-GDK/SDL.sln", gdk=True, no_cmake=True, ),
  105. "ubuntu-22.04": JobSpec(name="Ubuntu 22.04", priority=False, os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04", ),
  106. "ubuntu-latest": JobSpec(name="Ubuntu (latest)", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.Linux, artifact="SDL-ubuntu-latest", ),
  107. "ubuntu-24.04-arm64": JobSpec(name="Ubuntu 24.04 (ARM64)", priority=False, os=JobOs.Ubuntu24_04_arm, platform=SdlPlatform.Linux, artifact="SDL-ubuntu24.04-arm64", ),
  108. "steamrt3": JobSpec(name="Steam Linux Runtime 3.0 (x86_64)", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.Linux, artifact="SDL-steamrt3", container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest" ),
  109. "steamrt4": JobSpec(name="Steam Linux Runtime 4.0 (x86_64)", priority=True, os=JobOs.UbuntuLatest, platform=SdlPlatform.Linux, artifact="SDL-steamrt4", container="registry.gitlab.steamos.cloud/steamrt/steamrt4/sdk:latest", more_hard_deps = True, ),
  110. "steamrt4-arm64": JobSpec(name="Steam Linux Runtime 4.0 (arm64)", priority=False, os=JobOs.Ubuntu24_04_arm, platform=SdlPlatform.Linux, artifact="SDL-steamrt4-arm64", container="registry.gitlab.steamos.cloud/steamrt/steamrt4/sdk/arm64:latest", more_hard_deps = True, ),
  111. "ubuntu-intel-icx": JobSpec(name="Ubuntu 22.04 (Intel oneAPI)", priority=False, os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-oneapi", intel=IntelCompiler.Icx, ),
  112. "ubuntu-intel-icc": JobSpec(name="Ubuntu 22.04 (Intel Compiler)", priority=False, os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-icc", intel=IntelCompiler.Icc, ),
  113. "macos-framework-x64": JobSpec(name="MacOS (Framework) (x64)", priority=False, os=JobOs.Macos14, platform=SdlPlatform.MacOS, artifact="SDL-macos-framework", apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, ),
  114. "macos-framework-arm64": JobSpec(name="MacOS (Framework) (arm64)", priority=True, os=JobOs.MacosLatest, platform=SdlPlatform.MacOS, artifact=None, apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, xcode=True, ),
  115. "macos-26-framework-arm64": JobSpec(name="MacOS 26 (Framework) (arm64)",priority=False, os=JobOs.Macos26, platform=SdlPlatform.MacOS, artifact=None, apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, ),
  116. "macos-gnu-arm64": JobSpec(name="MacOS (GNU prefix)", priority=False, os=JobOs.MacosLatest, platform=SdlPlatform.MacOS, artifact="SDL-macos-arm64-gnu", apple_framework=False, apple_archs={AppleArch.Aarch64, }, ),
  117. "ios": JobSpec(name="iOS (CMake & xcode)", priority=True, os=JobOs.MacosLatest, platform=SdlPlatform.Ios, artifact="SDL-ios-arm64", xcode=True, ),
  118. "tvos": JobSpec(name="tvOS (CMake & xcode)", priority=True, os=JobOs.MacosLatest, platform=SdlPlatform.Tvos, artifact="SDL-tvos-arm64", xcode=True, ),
  119. "android-cmake": JobSpec(name="Android (CMake)", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact="SDL-android-arm64", android_abi="arm64-v8a", android_arch="aarch64", android_platform=23, ),
  120. "android-cmake-lean": JobSpec(name="Android (CMake, lean)", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact="SDL-lean-android-arm64", android_abi="arm64-v8a", android_arch="aarch64", android_platform=23, lean=True, ),
  121. "android-mk": JobSpec(name="Android (Android.mk)", priority=True, os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact=None, no_cmake=True, android_mk=True, ),
  122. "android-gradle": JobSpec(name="Android (Gradle)", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact=None, no_cmake=True, android_gradle=True, ),
  123. "emscripten": JobSpec(name="Emscripten", priority=True, os=JobOs.UbuntuLatest, platform=SdlPlatform.Emscripten, artifact="SDL-emscripten", ),
  124. "haiku": JobSpec(name="Haiku", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.Haiku, artifact="SDL-haiku-x64", container="ghcr.io/haiku/cross-compiler:x86_64-r1beta5", ),
  125. "loongarch64": JobSpec(name="LoongArch64", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.LoongArch64, artifact="SDL-loongarch64", ),
  126. "n3ds": JobSpec(name="Nintendo 3DS", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.N3ds, artifact="SDL-n3ds", container="devkitpro/devkitarm:latest", ),
  127. "ppc": JobSpec(name="PowerPC", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.PowerPC, artifact="SDL-ppc", container="dockcross/linux-ppc:latest", ),
  128. "ppc64": JobSpec(name="PowerPC64", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.PowerPC64, artifact="SDL-ppc64le", container="dockcross/linux-ppc64le:latest", ),
  129. "ps2": JobSpec(name="Sony PlayStation 2", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.Ps2, artifact="SDL-ps2", container="ps2dev/ps2dev:latest", ),
  130. "psp": JobSpec(name="Sony PlayStation Portable", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.Psp, artifact="SDL-psp", container="pspdev/pspdev:latest", ),
  131. "vita-pib": JobSpec(name="Sony PlayStation Vita (GLES w/ pib)", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.Vita, artifact="SDL-vita-pib", container="vitasdk/vitasdk:latest", vita_gles=VitaGLES.Pib, ),
  132. "vita-pvr": JobSpec(name="Sony PlayStation Vita (GLES w/ PVR_PSP2)", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.Vita, artifact="SDL-vita-pvr", container="vitasdk/vitasdk:latest", vita_gles=VitaGLES.Pvr, ),
  133. "riscos": JobSpec(name="RISC OS", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.Riscos, artifact="SDL-riscos", container="riscosdotinfo/riscos-gccsdk-4.7:latest", ),
  134. "netbsd": JobSpec(name="NetBSD", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.NetBSD, artifact="SDL-netbsd-x64", ),
  135. "openbsd": JobSpec(name="OpenBSD", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.OpenBSD, artifact="SDL-openbsd-x64", ),
  136. "freebsd": JobSpec(name="FreeBSD", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.FreeBSD, artifact="SDL-freebsd-x64", ),
  137. "ngage": JobSpec(name="N-Gage", priority=False, os=JobOs.WindowsLatest, platform=SdlPlatform.NGage, artifact="SDL-ngage", ),
  138. "djgpp": JobSpec(name="DOS (DJGPP)", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.DJGPP, artifact="SDL-djgpp", ),
  139. }
  140. class StaticLibType(Enum):
  141. STATIC_LIB = "SDL3-static.lib"
  142. A = "libSDL3.a"
  143. class SharedLibType(Enum):
  144. WIN32 = "SDL3.dll"
  145. CYGDLL = "cygSDL3.dll"
  146. SO_0 = "libSDL3.so.0"
  147. SO = "libSDL3.so"
  148. DYLIB = "libSDL3.0.dylib"
  149. FRAMEWORK = "SDL3.framework/Versions/A/SDL3"
  150. @dataclasses.dataclass(slots=True)
  151. class JobDetails:
  152. name: str
  153. key: str
  154. os: str
  155. platform: str
  156. artifact: str
  157. no_cmake: bool
  158. ccache: bool = False
  159. build_tests: bool = True
  160. container: str = ""
  161. cmake_build_type: str = "RelWithDebInfo"
  162. shell: str = "sh"
  163. sudo: str = "sudo"
  164. cmake_config_emulator: str = ""
  165. apk_packages: list[str] = dataclasses.field(default_factory=list)
  166. apt_packages: list[str] = dataclasses.field(default_factory=list)
  167. brew_packages: list[str] = dataclasses.field(default_factory=list)
  168. cmake_toolchain_file: str = ""
  169. cmake_arguments: list[str] = dataclasses.field(default_factory=list)
  170. cmake_generator: str = "Ninja"
  171. cmake_build_arguments: list[str] = dataclasses.field(default_factory=list)
  172. clang_tidy: bool = True
  173. cppflags: list[str] = dataclasses.field(default_factory=list)
  174. cc: str = ""
  175. cxx: str = ""
  176. cflags: list[str] = dataclasses.field(default_factory=list)
  177. cxxflags: list[str] = dataclasses.field(default_factory=list)
  178. ldflags: list[str] = dataclasses.field(default_factory=list)
  179. pollute_directories: list[str] = dataclasses.field(default_factory=list)
  180. use_cmake: bool = True
  181. shared: bool = True
  182. static: bool = True
  183. shared_lib: Optional[SharedLibType] = None
  184. static_lib: Optional[StaticLibType] = None
  185. run_tests: bool = True
  186. test_pkg_config: bool = True
  187. cc_from_cmake: bool = False
  188. source_cmd: str = ""
  189. pretest_cmd: str = ""
  190. java: bool = False
  191. android_apks: list[str] = dataclasses.field(default_factory=list)
  192. android_ndk: bool = False
  193. android_mk: bool = False
  194. android_gradle: bool = False
  195. minidump: bool = False
  196. intel: bool = False
  197. msys2_msystem: str = ""
  198. msys2_packages: list[str] = dataclasses.field(default_factory=list)
  199. cygwin_packages: list[str] = dataclasses.field(default_factory=list)
  200. werror: bool = True
  201. microsoft_gameinput: bool = False
  202. microsoft_gameinput_arch: str = ""
  203. msvc_vcvars_arch: str = ""
  204. msvc_vcvars_sdk: str = ""
  205. msvc_project: str = ""
  206. msvc_project_flags: list[str] = dataclasses.field(default_factory=list)
  207. setup_ninja: bool = False
  208. setup_libusb_arch: str = ""
  209. xcode_sdk: str = ""
  210. cpactions: bool = False
  211. setup_gdk_folder: str = ""
  212. cpactions_os: str = ""
  213. cpactions_version: str = ""
  214. cpactions_arch: str = ""
  215. cpactions_setup_cmd: str = ""
  216. cpactions_install_cmd: str = ""
  217. setup_vita_gles_type: str = ""
  218. check_sources: bool = False
  219. setup_python: bool = False
  220. pypi_packages: list[str] = dataclasses.field(default_factory=list)
  221. setup_gage_sdk_path: str = ""
  222. binutils_strings: str = "strings"
  223. ctest_args: str = ""
  224. def to_workflow(self, enable_artifacts: bool) -> dict[str, str|bool]:
  225. data = {
  226. "name": self.name,
  227. "key": self.key,
  228. "os": self.os,
  229. "ccache": self.ccache,
  230. "container": self.container if self.container else "",
  231. "platform": self.platform,
  232. "artifact": self.artifact,
  233. "enable-artifacts": enable_artifacts,
  234. "shell": self.shell,
  235. "msys2-msystem": self.msys2_msystem,
  236. "msys2-packages": my_shlex_join(self.msys2_packages),
  237. "cygwin-packages": my_shlex_join(self.cygwin_packages),
  238. "android-ndk": self.android_ndk,
  239. "java": self.java,
  240. "intel": self.intel,
  241. "apk-packages": my_shlex_join(self.apk_packages),
  242. "apt-packages": my_shlex_join(self.apt_packages),
  243. "test-pkg-config": self.test_pkg_config,
  244. "brew-packages": my_shlex_join(self.brew_packages),
  245. "pollute-directories": my_shlex_join(self.pollute_directories),
  246. "no-cmake": self.no_cmake,
  247. "build-tests": self.build_tests,
  248. "source-cmd": self.source_cmd,
  249. "pretest-cmd": self.pretest_cmd,
  250. "cmake-config-emulator": self.cmake_config_emulator,
  251. "cc": self.cc,
  252. "cxx": self.cxx,
  253. "cflags": my_shlex_join(self.cppflags + self.cflags),
  254. "cxxflags": my_shlex_join(self.cppflags + self.cxxflags),
  255. "ldflags": my_shlex_join(self.ldflags),
  256. "cmake-generator": self.cmake_generator,
  257. "cmake-toolchain-file": self.cmake_toolchain_file,
  258. "clang-tidy": self.clang_tidy,
  259. "cmake-arguments": my_shlex_join(self.cmake_arguments),
  260. "cmake-build-arguments": my_shlex_join(self.cmake_build_arguments),
  261. "shared": self.shared,
  262. "static": self.static,
  263. "shared-lib": self.shared_lib.value if self.shared_lib else None,
  264. "static-lib": self.static_lib.value if self.static_lib else None,
  265. "cmake-build-type": self.cmake_build_type,
  266. "run-tests": self.run_tests,
  267. "android-apks": my_shlex_join(self.android_apks),
  268. "android-gradle": self.android_gradle,
  269. "android-mk": self.android_mk,
  270. "werror": self.werror,
  271. "sudo": self.sudo,
  272. "microsoft-gameinput": self.microsoft_gameinput,
  273. "microsoft-gameinput-arch": self.microsoft_gameinput_arch,
  274. "msvc-vcvars-arch": self.msvc_vcvars_arch,
  275. "msvc-vcvars-sdk": self.msvc_vcvars_sdk,
  276. "msvc-project": self.msvc_project,
  277. "msvc-project-flags": my_shlex_join(self.msvc_project_flags),
  278. "setup-ninja": self.setup_ninja,
  279. "setup-libusb-arch": self.setup_libusb_arch,
  280. "cc-from-cmake": self.cc_from_cmake,
  281. "xcode-sdk": self.xcode_sdk,
  282. "cpactions": self.cpactions,
  283. "cpactions-os": self.cpactions_os,
  284. "cpactions-version": self.cpactions_version,
  285. "cpactions-arch": self.cpactions_arch,
  286. "cpactions-setup-cmd": self.cpactions_setup_cmd,
  287. "cpactions-install-cmd": self.cpactions_install_cmd,
  288. "setup-vita-gles-type": self.setup_vita_gles_type,
  289. "setup-gdk-folder": self.setup_gdk_folder,
  290. "check-sources": self.check_sources,
  291. "setup-python": self.setup_python,
  292. "pypi-packages": my_shlex_join(self.pypi_packages),
  293. "setup-ngage-sdk-path": self.setup_gage_sdk_path,
  294. "binutils-strings": self.binutils_strings,
  295. "ctest-args": self.ctest_args,
  296. }
  297. return {k: v for k, v in data.items() if v != ""}
  298. def my_shlex_join(s):
  299. def escape(s):
  300. if s[:1] == "'" and s[-1:] == "'":
  301. return s
  302. if set(s).intersection(set("; \t")):
  303. return f'"{s}"'
  304. return s
  305. return " ".join(escape(s))
  306. def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool, ctest_args: list[str]) -> JobDetails:
  307. job = JobDetails(
  308. name=spec.name,
  309. key=key,
  310. os=spec.os.value,
  311. artifact=spec.artifact or "",
  312. container=spec.container or "",
  313. platform=spec.platform.value,
  314. sudo="sudo",
  315. no_cmake=spec.no_cmake,
  316. )
  317. if job.os.startswith("ubuntu"):
  318. job.apt_packages.extend([
  319. "ninja-build",
  320. "pkg-config",
  321. ])
  322. pretest_cmd = []
  323. if trackmem_symbol_names:
  324. pretest_cmd.append("export SDL_TRACKMEM_SYMBOL_NAMES=1")
  325. else:
  326. pretest_cmd.append("export SDL_TRACKMEM_SYMBOL_NAMES=0")
  327. win32 = spec.platform in (SdlPlatform.Msys2, SdlPlatform.Msvc)
  328. fpic = None
  329. build_parallel = True
  330. if spec.lean:
  331. job.cmake_arguments.append("-DSDL_LEAN_AND_MEAN=TRUE")
  332. if win32:
  333. job.cmake_arguments.append("-DSDLTEST_PROCDUMP=ON")
  334. job.minidump = True
  335. if spec.intel is not None:
  336. match spec.intel:
  337. case IntelCompiler.Icx:
  338. job.cc = "icx"
  339. job.cxx = "icpx"
  340. case IntelCompiler.Icc:
  341. job.cc = "icc"
  342. job.cxx = "icpc"
  343. # Disable deprecation warning
  344. job.cppflags.append("-diag-disable=10441")
  345. # Avoid 'Catastrophic error: cannot open precompiled header file'
  346. job.cmake_arguments.append("-DCMAKE_DISABLE_PRECOMPILE_HEADERS:BOOL=ON")
  347. job.clang_tidy = False
  348. case _:
  349. raise ValueError(f"Invalid intel={spec.intel}")
  350. job.source_cmd = f"source /opt/intel/oneapi/setvars.sh;"
  351. job.intel = True
  352. job.shell = "bash"
  353. job.cmake_arguments.extend((
  354. f"-DCMAKE_C_COMPILER={job.cc}",
  355. f"-DCMAKE_CXX_COMPILER={job.cxx}",
  356. "-DCMAKE_SYSTEM_NAME=Linux",
  357. ))
  358. match spec.platform:
  359. case SdlPlatform.Msvc:
  360. job.setup_ninja = not spec.gdk
  361. job.clang_tidy = False # complains about \threadsafety: "unknown command tag name [clang-diagnostic-documentation-unknown-command]"
  362. job.msvc_project = spec.msvc_project if spec.msvc_project else ""
  363. job.msvc_project_flags.append("-p:TreatWarningsAsError=true")
  364. job.test_pkg_config = False
  365. job.shared_lib = SharedLibType.WIN32
  366. job.static_lib = StaticLibType.STATIC_LIB
  367. job.cmake_arguments.extend((
  368. "-DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=ProgramDatabase",
  369. "-DCMAKE_EXE_LINKER_FLAGS=-DEBUG",
  370. "-DCMAKE_SHARED_LINKER_FLAGS=-DEBUG",
  371. ))
  372. job.cmake_arguments.append("'-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded$<$<CONFIG:Debug>:Debug>'")
  373. if spec.clang_cl:
  374. job.cmake_arguments.extend((
  375. "-DCMAKE_C_COMPILER=clang-cl",
  376. "-DCMAKE_CXX_COMPILER=clang-cl",
  377. ))
  378. match spec.msvc_arch:
  379. case MsvcArch.X86:
  380. job.cflags.append("/clang:-m32")
  381. job.cxxflags.append("/clang:-m32")
  382. job.ldflags.append("/MACHINE:X86")
  383. case MsvcArch.X64:
  384. job.cflags.append("/clang:-m64")
  385. job.cxxflags.append("/clang:-m64")
  386. job.ldflags.append("/MACHINE:X64")
  387. case _:
  388. raise ValueError(f"Unsupported clang-cl architecture (arch={spec.msvc_arch})")
  389. if spec.msvc_project:
  390. match spec.msvc_arch:
  391. case MsvcArch.X86:
  392. msvc_platform = "Win32"
  393. case MsvcArch.X64:
  394. msvc_platform = "x64"
  395. case MsvcArch.Arm64:
  396. msvc_platform = "ARM64"
  397. case _:
  398. raise ValueError(f"Unsupported vcxproj architecture (arch={spec.msvc_arch})")
  399. if spec.gdk:
  400. msvc_platform = f"Gaming.Desktop.{msvc_platform}"
  401. job.msvc_project_flags.append(f"-p:Platform={msvc_platform}")
  402. match spec.msvc_arch:
  403. case MsvcArch.X86:
  404. job.msvc_vcvars_arch = "x64_x86"
  405. case MsvcArch.X64:
  406. job.msvc_vcvars_arch = "x64"
  407. case MsvcArch.Arm64:
  408. job.msvc_vcvars_arch = "x64_arm64"
  409. job.run_tests = False
  410. if spec.gdk:
  411. job.setup_gdk_folder = "VisualC-GDK"
  412. else:
  413. match spec.msvc_arch:
  414. case MsvcArch.X86:
  415. job.setup_libusb_arch = "x86"
  416. case MsvcArch.X64:
  417. job.setup_libusb_arch = "x64"
  418. job.microsoft_gameinput = True
  419. match spec.msvc_arch:
  420. case MsvcArch.X64:
  421. job.microsoft_gameinput_arch = "x64"
  422. case MsvcArch.Arm64:
  423. job.microsoft_gameinput_arch = "arm64"
  424. job.cflags.append("-I$GAMEINPUT_INCLUDE")
  425. job.cxxflags.append("-I$GAMEINPUT_INCLUDE")
  426. case SdlPlatform.Linux:
  427. if spec.name.startswith("Ubuntu"):
  428. assert spec.os.value.startswith("ubuntu-")
  429. job.apt_packages.extend((
  430. "ccache",
  431. "gnome-desktop-testing",
  432. "libasound2-dev",
  433. "libpulse-dev",
  434. "libaudio-dev",
  435. "libjack-dev",
  436. "libsndio-dev",
  437. "libusb-1.0-0-dev",
  438. "libx11-dev",
  439. "libxext-dev",
  440. "libxrandr-dev",
  441. "libxcursor-dev",
  442. "libxfixes-dev",
  443. "libxi-dev",
  444. "libxss-dev",
  445. "libxtst-dev",
  446. "libwayland-dev",
  447. "libxkbcommon-dev",
  448. "libdrm-dev",
  449. "libgbm-dev",
  450. "libgl1-mesa-dev",
  451. "libgles2-mesa-dev",
  452. "libegl1-mesa-dev",
  453. "libdbus-1-dev",
  454. "libibus-1.0-dev",
  455. "libudev-dev",
  456. "fcitx-libs-dev",
  457. "libfribidi-dev",
  458. # testffmpeg
  459. "libavcodec-dev",
  460. "libavfilter-dev",
  461. "libavutil-dev",
  462. "libswresample-dev",
  463. "libswscale-dev",
  464. ))
  465. match = re.match(r"ubuntu-(?P<year>[0-9]+)\.(?P<month>[0-9]+|latest).*", spec.os.value)
  466. ubuntu_ge_22 = True
  467. if match and match["month"] != "latest":
  468. ubuntu_year, ubuntu_month = [int(match["year"]), int(match["month"])]
  469. ubuntu_ge_22 = ubuntu_year >= 22
  470. job.apt_packages.extend(("libpipewire-0.3-dev", "libdecor-0-dev"))
  471. job.apt_packages.extend((
  472. "libunwind-dev", # For SDL_test memory tracking
  473. ))
  474. job.ccache = True
  475. if trackmem_symbol_names:
  476. # older libunwind is slow
  477. job.cmake_arguments.append("-DSDLTEST_TIMEOUT_MULTIPLIER=2")
  478. job.shared_lib = SharedLibType.SO_0
  479. job.static_lib = StaticLibType.A
  480. fpic = True
  481. job.cmake_arguments.append("-DSDLTEST_GDB=ON")
  482. job.apt_packages.append("gdb")
  483. if spec.more_hard_deps:
  484. # Some distros prefer to make important dependencies
  485. # mandatory, so that SDL won't start up but lack expected
  486. # functionality if they're missing
  487. job.cmake_arguments.extend([
  488. "-DSDL_ALSA_SHARED=OFF",
  489. "-DSDL_FRIBIDI_SHARED=OFF",
  490. "-DSDL_HIDAPI_LIBUSB_SHARED=OFF",
  491. "-DSDL_PULSEAUDIO_SHARED=OFF",
  492. "-DSDL_X11_SHARED=OFF",
  493. "-DSDL_WAYLAND_LIBDECOR_SHARED=OFF",
  494. "-DSDL_WAYLAND_SHARED=OFF",
  495. ])
  496. case SdlPlatform.Ios | SdlPlatform.Tvos:
  497. job.brew_packages.extend([
  498. "ccache",
  499. "ninja",
  500. ])
  501. job.ccache = True
  502. job.clang_tidy = False
  503. job.run_tests = False
  504. job.test_pkg_config = False
  505. job.shared_lib = SharedLibType.DYLIB
  506. job.static_lib = StaticLibType.A
  507. match spec.platform:
  508. case SdlPlatform.Ios:
  509. if spec.xcode:
  510. job.xcode_sdk = 'iphoneos'
  511. job.cmake_arguments.extend([
  512. "-DCMAKE_SYSTEM_NAME=iOS",
  513. "-DCMAKE_OSX_ARCHITECTURES=\"arm64\"",
  514. "-DCMAKE_OSX_DEPLOYMENT_TARGET=11.0",
  515. ])
  516. case SdlPlatform.Tvos:
  517. if spec.xcode:
  518. job.xcode_sdk = 'appletvos'
  519. job.cmake_arguments.extend([
  520. "-DCMAKE_SYSTEM_NAME=tvOS",
  521. "-DCMAKE_OSX_ARCHITECTURES=\"arm64\"",
  522. "-DCMAKE_OSX_DEPLOYMENT_TARGET=11.0",
  523. ])
  524. case SdlPlatform.MacOS:
  525. if spec.apple_framework:
  526. job.static = False
  527. job.clang_tidy = False
  528. job.test_pkg_config = False
  529. job.cmake_arguments.extend((
  530. "'-DCMAKE_OSX_ARCHITECTURES=x86_64;arm64'",
  531. "-DCMAKE_OSX_DEPLOYMENT_TARGET=10.13",
  532. "-DSDL_FRAMEWORK=ON",
  533. ))
  534. job.shared_lib = SharedLibType.FRAMEWORK
  535. else:
  536. job.clang_tidy = True
  537. job.cmake_arguments.extend((
  538. "-DCMAKE_OSX_ARCHITECTURES=arm64",
  539. "-DCMAKE_OSX_DEPLOYMENT_TARGET=10.13",
  540. "-DCLANG_TIDY_BINARY=$(brew --prefix llvm)/bin/clang-tidy",
  541. ))
  542. job.brew_packages.extend((
  543. # Brew provides a single architecture (aarch64), so it's not usable for fat libraries
  544. "ffmpeg", # testffmpeg
  545. ))
  546. job.shared_lib = SharedLibType.DYLIB
  547. job.static_lib = StaticLibType.A
  548. job.ccache = True
  549. job.apt_packages = []
  550. job.brew_packages.extend((
  551. "ninja",
  552. ))
  553. if job.ccache:
  554. job.brew_packages.append("ccache")
  555. if job.clang_tidy:
  556. job.brew_packages.append("llvm")
  557. if spec.xcode:
  558. job.xcode_sdk = "macosx"
  559. case SdlPlatform.Android:
  560. job.android_gradle = spec.android_gradle
  561. job.android_mk = spec.android_mk
  562. job.apt_packages.append("ccache")
  563. job.run_tests = False
  564. job.shared_lib = SharedLibType.SO
  565. job.static_lib = StaticLibType.A
  566. if spec.android_mk or not spec.no_cmake:
  567. job.android_ndk = True
  568. if spec.android_gradle or not spec.no_cmake:
  569. job.java = True
  570. if spec.android_mk or spec.android_gradle:
  571. job.apt_packages = []
  572. if not spec.no_cmake:
  573. job.ccache = True
  574. job.cmake_arguments.extend((
  575. f"-DANDROID_PLATFORM={spec.android_platform}",
  576. f"-DANDROID_ABI={spec.android_abi}",
  577. ))
  578. job.cmake_toolchain_file = "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake"
  579. job.cc = f"${{ANDROID_NDK_HOME}}/toolchains/llvm/prebuilt/linux-x86_64/bin/clang --target={spec.android_arch}-none-linux-androideabi{spec.android_platform}"
  580. job.android_apks = [
  581. "testaudiorecording-apk",
  582. "testautomation-apk",
  583. "testcontroller-apk",
  584. "testmultiaudio-apk",
  585. "testsprite-apk",
  586. ]
  587. # -fPIC is required after updating NDK from 21 to 28
  588. job.cflags.append("-fPIC")
  589. job.cxxflags.append("-fPIC")
  590. case SdlPlatform.Emscripten:
  591. emscripten_tests = not spec.priority
  592. job.clang_tidy = False # clang-tidy does not understand -gsource-map
  593. job.shared = False
  594. job.ccache = True
  595. job.apt_packages.append("ccache")
  596. job.cmake_config_emulator = "emcmake"
  597. job.cmake_build_type = "Debug"
  598. job.test_pkg_config = False
  599. job.cmake_arguments.extend((
  600. "-DSDLTEST_BROWSER=chrome",
  601. "-DSDLTEST_TIMEOUT_MULTIPLIER=4",
  602. "-DSDLTEST_CHROME_BINARY=${CHROME_BINARY}",
  603. ))
  604. job.cflags.extend((
  605. "-gsource-map",
  606. "-ffile-prefix-map=${PWD}=/SDL",
  607. ))
  608. job.ldflags.extend((
  609. "--source-map-base", "/",
  610. ))
  611. pretest_cmd.extend((
  612. "# Start local HTTP server",
  613. "cmake --build build --target serve-sdl-tests --verbose &",
  614. "chrome --version",
  615. "chromedriver --version",
  616. ))
  617. job.static_lib = StaticLibType.A
  618. if emscripten_tests:
  619. job.setup_python = True
  620. job.pypi_packages.append("selenium")
  621. else:
  622. job.cmake_arguments.extend((
  623. "-DSDL_TESTS=OFF",
  624. ))
  625. job.run_tests = False
  626. case SdlPlatform.Ps2:
  627. job.ccache = False # actions/ccache does not work in psp container (incompatible tar of busybox)
  628. build_parallel = False
  629. job.shared = False
  630. job.sudo = ""
  631. job.apt_packages = []
  632. job.apk_packages = ["ccache", "cmake", "gmp", "mpc1", "mpfr4", "ninja", "pkgconf", "git", ]
  633. job.cmake_toolchain_file = "${PS2DEV}/ps2sdk/ps2dev.cmake"
  634. job.clang_tidy = False
  635. job.run_tests = False
  636. job.shared = False
  637. job.cc = "mips64r5900el-ps2-elf-gcc"
  638. job.ldflags = ["-L${PS2DEV}/ps2sdk/ee/lib", "-L${PS2DEV}/gsKit/lib", "-L${PS2DEV}/ps2sdk/ports/lib", ]
  639. job.static_lib = StaticLibType.A
  640. case SdlPlatform.Psp:
  641. job.ccache = False # actions/ccache does not work in psp container (incompatible tar of busybox)
  642. build_parallel = False
  643. job.sudo = ""
  644. job.apt_packages = []
  645. job.apk_packages = ["ccache", "cmake", "gmp", "mpc1", "mpfr4", "ninja", "pkgconf", ]
  646. job.cmake_toolchain_file = "${PSPDEV}/psp/share/pspdev.cmake"
  647. job.clang_tidy = False
  648. job.run_tests = False
  649. job.shared = False
  650. job.cc = "psp-gcc"
  651. job.ldflags = ["-L${PSPDEV}/lib", "-L${PSPDEV}/psp/lib", "-L${PSPDEV}/psp/sdk/lib", ]
  652. job.pollute_directories = ["${PSPDEV}/include", "${PSPDEV}/psp/include", "${PSPDEV}/psp/sdk/include", ]
  653. job.static_lib = StaticLibType.A
  654. case SdlPlatform.Vita:
  655. job.ccache = True
  656. job.sudo = ""
  657. job.apt_packages = []
  658. job.apk_packages = ["ccache", "cmake", "ninja", "pkgconf", "bash", "tar"]
  659. job.cmake_toolchain_file = "${VITASDK}/share/vita.toolchain.cmake"
  660. assert spec.vita_gles is not None
  661. job.setup_vita_gles_type = {
  662. VitaGLES.Pib: "pib",
  663. VitaGLES.Pvr: "pvr",
  664. }[spec.vita_gles]
  665. job.cmake_arguments.extend((
  666. f"-DVIDEO_VITA_PIB={ 'true' if spec.vita_gles == VitaGLES.Pib else 'false' }",
  667. f"-DVIDEO_VITA_PVR={ 'true' if spec.vita_gles == VitaGLES.Pvr else 'false' }",
  668. "-DSDL_ARMNEON=ON",
  669. "-DSDL_ARMSIMD=ON",
  670. ))
  671. # Fix vita.toolchain.cmake (https://github.com/vitasdk/vita-toolchain/pull/253)
  672. job.source_cmd = r"""sed -i -E "s#set\\( PKG_CONFIG_EXECUTABLE \"\\$\\{VITASDK}/bin/arm-vita-eabi-pkg-config\" \\)#set\\( PKG_CONFIG_EXECUTABLE \"${VITASDK}/bin/arm-vita-eabi-pkg-config\" CACHE PATH \"Path of pkg-config executable\" \\)#" ${VITASDK}/share/vita.toolchain.cmake"""
  673. job.clang_tidy = False
  674. job.run_tests = False
  675. job.shared = False
  676. job.cc = "arm-vita-eabi-gcc"
  677. job.static_lib = StaticLibType.A
  678. case SdlPlatform.Haiku:
  679. job.ccache = True
  680. fpic = False
  681. job.run_tests = False
  682. job.apt_packages.append("ccache")
  683. job.cc = "x86_64-unknown-haiku-gcc"
  684. job.cxx = "x86_64-unknown-haiku-g++"
  685. job.sudo = ""
  686. job.cmake_arguments.extend((
  687. f"-DCMAKE_C_COMPILER={job.cc}",
  688. f"-DCMAKE_CXX_COMPILER={job.cxx}",
  689. "-DCMAKE_SYSTEM_NAME=Haiku",
  690. ))
  691. job.shared_lib = SharedLibType.SO_0
  692. job.static_lib = StaticLibType.A
  693. case SdlPlatform.PowerPC64 | SdlPlatform.PowerPC:
  694. job.ccache = True
  695. # FIXME: Enable SDL_WERROR
  696. job.werror = False
  697. job.clang_tidy = False
  698. job.run_tests = False
  699. job.sudo = ""
  700. job.apt_packages = ["ccache"]
  701. job.shared_lib = SharedLibType.SO_0
  702. job.static_lib = StaticLibType.A
  703. job.cmake_arguments.extend((
  704. "-DSDL_UNIX_CONSOLE_BUILD=ON",
  705. ))
  706. case SdlPlatform.LoongArch64:
  707. job.ccache = True
  708. fpic = True
  709. job.run_tests = False
  710. job.apt_packages.append("ccache")
  711. job.cc = "${LOONGARCH64_CC}"
  712. job.cxx = "${LOONGARCH64_CXX}"
  713. job.cmake_arguments.extend((
  714. f"-DCMAKE_C_COMPILER={job.cc}",
  715. f"-DCMAKE_CXX_COMPILER={job.cxx}",
  716. "-DSDL_UNIX_CONSOLE_BUILD=ON",
  717. "-DCMAKE_SYSTEM_NAME=Linux",
  718. ))
  719. job.shared_lib = SharedLibType.SO_0
  720. job.static_lib = StaticLibType.A
  721. case SdlPlatform.N3ds:
  722. job.cmake_generator = "Unix Makefiles"
  723. job.cmake_build_arguments.append("-j$(nproc)")
  724. job.ccache = False
  725. job.shared = False
  726. job.apt_packages = []
  727. job.clang_tidy = False
  728. job.run_tests = False
  729. job.cc_from_cmake = True
  730. job.cmake_toolchain_file = "${DEVKITPRO}/cmake/3DS.cmake"
  731. job.binutils_strings = "/opt/devkitpro/devkitARM/bin/arm-none-eabi-strings"
  732. job.static_lib = StaticLibType.A
  733. case SdlPlatform.Msys2:
  734. job.ccache = True
  735. job.shell = "msys2 {0}"
  736. assert spec.msys2_platform
  737. job.msys2_msystem = spec.msys2_platform.value
  738. job.shared_lib = SharedLibType.WIN32
  739. job.static_lib = StaticLibType.A
  740. msys2_env = {
  741. "mingw32": "mingw-w64-i686",
  742. "mingw64": "mingw-w64-x86_64",
  743. "clang64": "mingw-w64-clang-x86_64",
  744. "ucrt64": "mingw-w64-ucrt-x86_64",
  745. }[spec.msys2_platform.value]
  746. job.msys2_packages.extend([
  747. f"{msys2_env}-cc",
  748. f"{msys2_env}-cmake",
  749. f"{msys2_env}-ffmpeg",
  750. f"{msys2_env}-ninja",
  751. f"{msys2_env}-pkg-config",
  752. ])
  753. if spec.msys2_platform not in (Msys2Platform.Mingw32, ):
  754. job.msys2_packages.append(f"{msys2_env}-perl")
  755. job.msys2_packages.append(f"{msys2_env}-clang-tools-extra")
  756. if job.ccache:
  757. job.msys2_packages.append(f"{msys2_env}-ccache")
  758. job.microsoft_gameinput = True
  759. job.cflags.append("-I$GAMEINPUT_INCLUDE")
  760. job.cxxflags.append("-I$GAMEINPUT_INCLUDE")
  761. case SdlPlatform.Cygwin:
  762. job.ccache = False # Missing evict-older-than option
  763. job.clang_tidy = False # error finding files [clang-diagnostic-error] cause might be space in command path
  764. job.test_pkg_config = False # Linefeed issue in test_pkgconfig.sh
  765. job.shell = "bash --noprofile --norc -eo pipefail -o igncr {0}"
  766. job.shared_lib = SharedLibType.CYGDLL
  767. job.static_lib = StaticLibType.A
  768. job.cmake_arguments.append("-DSDLTEST_GDB=ON")
  769. job.cygwin_packages.extend([
  770. "cmake",
  771. "gcc-core",
  772. "gcc-g++",
  773. "gdb",
  774. "ninja",
  775. "pkg-config",
  776. "perl",
  777. "python",
  778. ])
  779. case SdlPlatform.Riscos:
  780. job.ccache = False # FIXME: enable when container gets upgrade
  781. # FIXME: Enable SDL_WERROR
  782. job.werror = False
  783. job.apt_packages = ["ccache", "cmake", "ninja-build"]
  784. job.test_pkg_config = False
  785. job.shared = False
  786. job.run_tests = False
  787. job.sudo = ""
  788. job.cmake_arguments.extend((
  789. "-DRISCOS:BOOL=ON",
  790. "-DCMAKE_DISABLE_PRECOMPILE_HEADERS:BOOL=ON",
  791. "-DSDL_GCC_ATOMICS:BOOL=OFF",
  792. ))
  793. job.cmake_toolchain_file = "/home/riscos/env/toolchain-riscos.cmake"
  794. job.static_lib = StaticLibType.A
  795. case SdlPlatform.FreeBSD | SdlPlatform.NetBSD | SdlPlatform.OpenBSD:
  796. job.cpactions = True
  797. job.no_cmake = True
  798. job.run_tests = False
  799. job.apt_packages = []
  800. job.shared_lib = SharedLibType.SO_0
  801. job.static_lib = StaticLibType.A
  802. match spec.platform:
  803. case SdlPlatform.FreeBSD:
  804. job.cpactions_os = "freebsd"
  805. job.cpactions_version = "14.3"
  806. job.cpactions_arch = "x86-64"
  807. job.cpactions_setup_cmd = "sudo pkg update"
  808. job.cpactions_install_cmd = "sudo pkg install -y cmake ninja 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"
  809. job.cmake_arguments.extend((
  810. "-DSDL_CHECK_REQUIRED_INCLUDES=/usr/local/include",
  811. "-DSDL_CHECK_REQUIRED_LINK_OPTIONS=-L/usr/local/lib",
  812. ))
  813. case SdlPlatform.NetBSD:
  814. job.cpactions_os = "netbsd"
  815. job.cpactions_version = "10.1"
  816. job.cpactions_arch = "x86-64"
  817. job.cpactions_setup_cmd = "export PATH=\"/usr/pkg/sbin:/usr/pkg/bin:/sbin:$PATH\"; export PKG_CONFIG_PATH=\"/usr/pkg/lib/pkgconfig\";export PKG_PATH=\"https://cdn.netBSD.org/pub/pkgsrc/packages/NetBSD/$(uname -p)/$(uname -r|cut -f \"1 2\" -d.)/All/\";echo \"PKG_PATH=$PKG_PATH\";echo \"uname -a -> \"$(uname -a)\"\";sudo -E sysctl -w security.pax.aslr.enabled=0;sudo -E sysctl -w security.pax.aslr.global=0;sudo -E pkgin clean;sudo -E pkgin update"
  818. job.cpactions_install_cmd = "sudo -E pkgin -y install cmake dbus pkgconf ninja-build pulseaudio libxkbcommon wayland wayland-protocols libinotify libusb1"
  819. case SdlPlatform.OpenBSD:
  820. job.cpactions_os = "openbsd"
  821. job.cpactions_version = "7.7"
  822. job.cpactions_arch = "x86-64"
  823. job.cpactions_setup_cmd = "sudo pkg_add -u"
  824. job.cpactions_install_cmd = "sudo pkg_add cmake ninja pkgconf wayland wayland-protocols libxkbcommon libinotify pulseaudio dbus ibus"
  825. case SdlPlatform.NGage:
  826. build_parallel = False
  827. job.cmake_build_type = "Release"
  828. job.setup_ninja = True
  829. job.static_lib = StaticLibType.STATIC_LIB
  830. job.shared_lib = None
  831. job.clang_tidy = False
  832. job.werror = False # FIXME: enable SDL_WERROR
  833. job.shared = False
  834. job.run_tests = False
  835. job.setup_gage_sdk_path = "C:/ngagesdk"
  836. job.cmake_toolchain_file = "C:/ngagesdk/cmake/ngage-toolchain.cmake"
  837. job.test_pkg_config = False
  838. case SdlPlatform.DJGPP:
  839. build_parallel = False
  840. job.ccache = True
  841. job.apt_packages = ["ccache", "libfl-dev"] # djgpp needs libfl.so.2
  842. job.cmake_build_type = "Release"
  843. job.setup_ninja = True
  844. job.static_lib = StaticLibType.A
  845. job.shared_lib = None
  846. job.clang_tidy = False
  847. job.werror = False # FIXME: enable SDL_WERROR
  848. job.shared = False
  849. job.run_tests = False
  850. job.test_pkg_config = False
  851. job.cmake_toolchain_file = "$GITHUB_WORKSPACE/build-scripts/i586-pc-msdosdjgpp.cmake"
  852. case _:
  853. raise ValueError(f"Unsupported platform={spec.platform}")
  854. if "ubuntu" in spec.name.lower():
  855. job.check_sources = True
  856. job.setup_python = True
  857. if job.ccache:
  858. job.cmake_arguments.extend((
  859. "-DCMAKE_C_COMPILER_LAUNCHER=ccache",
  860. "-DCMAKE_CXX_COMPILER_LAUNCHER=ccache",
  861. ))
  862. job.ctest_args = shlex.join(ctest_args)
  863. if not build_parallel:
  864. job.cmake_build_arguments.append("-j1")
  865. if job.cflags or job.cppflags:
  866. job.cmake_arguments.append(f"-DCMAKE_C_FLAGS=\"{my_shlex_join(job.cflags + job.cppflags)}\"")
  867. if job.cxxflags or job.cppflags:
  868. job.cmake_arguments.append(f"-DCMAKE_CXX_FLAGS=\"{my_shlex_join(job.cxxflags + job.cppflags)}\"")
  869. if job.ldflags:
  870. job.cmake_arguments.append(f"-DCMAKE_SHARED_LINKER_FLAGS=\"{my_shlex_join(job.ldflags)}\"")
  871. job.cmake_arguments.append(f"-DCMAKE_EXE_LINKER_FLAGS=\"{my_shlex_join(job.ldflags)}\"")
  872. job.pretest_cmd = "\n".join(pretest_cmd)
  873. def tf(b):
  874. return "ON" if b else "OFF"
  875. if fpic is not None:
  876. job.cmake_arguments.append(f"-DCMAKE_POSITION_INDEPENDENT_CODE={tf(fpic)}")
  877. if job.no_cmake:
  878. job.cmake_arguments = []
  879. return job
  880. def spec_to_platform(spec: JobSpec, key: str, enable_artifacts: bool, trackmem_symbol_names: bool, ctest_args:list[str]) -> dict[str, str|bool]:
  881. logger.info("spec=%r", spec)
  882. job = spec_to_job(
  883. spec,
  884. key=key,
  885. trackmem_symbol_names=trackmem_symbol_names,
  886. ctest_args=ctest_args,
  887. )
  888. logger.info("job=%r", job)
  889. platform = job.to_workflow(enable_artifacts=enable_artifacts)
  890. logger.info("platform=%r", platform)
  891. return platform
  892. def main():
  893. parser = argparse.ArgumentParser(allow_abbrev=False)
  894. parser.add_argument("--github-variable-prefix", default="platforms")
  895. parser.add_argument("--github-ci", action="store_true")
  896. parser.add_argument("--verbose", action="store_true")
  897. parser.add_argument("--commit-message-file")
  898. parser.add_argument("--no-artifact", dest="enable_artifacts", action="store_false")
  899. parser.add_argument("--trackmem-symbol-names", dest="trackmem_symbol_names", action="store_true")
  900. parser.add_argument("--priority-only", dest="priority_only", action="store_true")
  901. args = parser.parse_args()
  902. logging.basicConfig(level=logging.INFO if args.verbose else logging.WARNING)
  903. remaining_keys = set(JOB_SPECS.keys())
  904. all_level_keys = (
  905. # Level 1
  906. (
  907. "android-mk",
  908. ),
  909. )
  910. filters = []
  911. ctest_args = []
  912. if args.commit_message_file:
  913. with open(args.commit_message_file, "r") as f:
  914. commit_message = f.read()
  915. for m in re.finditer(r"\[sdl-ci-filter (.*)]", commit_message, flags=re.M):
  916. filters.append(m.group(1).strip(" \t\n\r\t'\""))
  917. if re.search(r"\[sdl-ci-artifacts?]", commit_message, flags=re.M):
  918. args.enable_artifacts = True
  919. if re.search(r"\[sdl-ci-(full-)?trackmem(-symbol-names)?]", commit_message, flags=re.M):
  920. args.trackmem_symbol_names = True
  921. for m in re.finditer(r"\[sdl-ci-ctest-args? (.*)]", commit_message, flags=re.M):
  922. ctest_args.extend(shlex.split(m.group(1)))
  923. if not filters:
  924. if args.priority_only:
  925. filters.extend(spec_id for spec_id, spec in JOB_SPECS.items() if spec.priority)
  926. else:
  927. filters.append("*")
  928. logger.info("filters: %r", filters)
  929. all_level_platforms = {}
  930. all_platforms = {key: spec_to_platform(spec, key=key, enable_artifacts=args.enable_artifacts, trackmem_symbol_names=args.trackmem_symbol_names, ctest_args=ctest_args) for key, spec in JOB_SPECS.items()}
  931. for level_i, level_keys in enumerate(all_level_keys, 1):
  932. level_key = f"level{level_i}"
  933. logger.info("Level %d: keys=%r", level_i, level_keys)
  934. assert all(k in remaining_keys for k in level_keys)
  935. level_platforms = tuple(all_platforms[key] for key in level_keys)
  936. remaining_keys.difference_update(level_keys)
  937. all_level_platforms[level_key] = level_platforms
  938. logger.info("=" * 80)
  939. logger.info("Keys before filter: %r", remaining_keys)
  940. filtered_remaining_keys = set()
  941. for filter in filters:
  942. filtered_remaining_keys.update(fnmatch.filter(remaining_keys, filter))
  943. logger.info("Keys after filter: %r", filtered_remaining_keys)
  944. remaining_keys = filtered_remaining_keys
  945. logger.info("Remaining: %r", remaining_keys)
  946. all_level_platforms["others"] = tuple(all_platforms[key] for key in remaining_keys)
  947. if args.github_ci:
  948. for level, platforms in all_level_platforms.items():
  949. platforms_json = json.dumps(platforms)
  950. txt = f"{args.github_variable_prefix}-{level}={platforms_json}"
  951. logger.info("%s", txt)
  952. if "GITHUB_OUTPUT" in os.environ:
  953. with open(os.environ["GITHUB_OUTPUT"], "a") as f:
  954. f.write(txt)
  955. f.write("\n")
  956. else:
  957. logger.warning("GITHUB_OUTPUT not defined")
  958. return 0
  959. if __name__ == "__main__":
  960. raise SystemExit(main())