1
0

create-test-plan.py 50 KB

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