create-test-plan.py 47 KB

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