1
0

create-test-plan.py 51 KB

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