summaryrefslogtreecommitdiff
path: root/src/contrib/SDL-3.2.20/build-scripts/setup-gdk-desktop.py
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-08-30 16:53:58 -0700
committer3gg <3gg@shellblade.net>2025-08-30 16:53:58 -0700
commit6aaedb813fa11ba0679c3051bc2eb28646b9506c (patch)
tree34acbfc9840e02cb4753e6306ea7ce978bf8b58e /src/contrib/SDL-3.2.20/build-scripts/setup-gdk-desktop.py
parent8f228ade99dd3d4c8da9b78ade1815c9adf85c8f (diff)
Update to SDL3
Diffstat (limited to 'src/contrib/SDL-3.2.20/build-scripts/setup-gdk-desktop.py')
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/setup-gdk-desktop.py303
1 files changed, 303 insertions, 0 deletions
diff --git a/src/contrib/SDL-3.2.20/build-scripts/setup-gdk-desktop.py b/src/contrib/SDL-3.2.20/build-scripts/setup-gdk-desktop.py
new file mode 100755
index 0000000..d2309a0
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/build-scripts/setup-gdk-desktop.py
@@ -0,0 +1,303 @@
1#!/usr/bin/env python
2
3import argparse
4import functools
5import logging
6import os
7from pathlib import Path
8import re
9import shutil
10import subprocess
11import tempfile
12import textwrap
13import urllib.request
14import zipfile
15
16# Update both variables when updating the GDK
17GIT_REF = "June_2024_Update_1"
18GDK_EDITION = "240601" # YYMMUU
19
20logger = logging.getLogger(__name__)
21
22class GdDesktopConfigurator:
23 def __init__(self, gdk_path, arch, vs_folder, vs_version=None, vs_toolset=None, temp_folder=None, git_ref=None, gdk_edition=None):
24 self.git_ref = git_ref or GIT_REF
25 self.gdk_edition = gdk_edition or GDK_EDITION
26 self.gdk_path = gdk_path
27 self.temp_folder = temp_folder or Path(tempfile.gettempdir())
28 self.dl_archive_path = Path(self.temp_folder) / f"{ self.git_ref }.zip"
29 self.gdk_extract_path = Path(self.temp_folder) / f"GDK-{ self.git_ref }"
30 self.arch = arch
31 self.vs_folder = vs_folder
32 self._vs_version = vs_version
33 self._vs_toolset = vs_toolset
34
35 def download_archive(self) -> None:
36 gdk_url = f"https://github.com/microsoft/GDK/archive/refs/tags/{ GIT_REF }.zip"
37 logger.info("Downloading %s to %s", gdk_url, self.dl_archive_path)
38 urllib.request.urlretrieve(gdk_url, self.dl_archive_path)
39 assert self.dl_archive_path.is_file()
40
41 def extract_zip_archive(self) -> None:
42 extract_path = self.gdk_extract_path.parent
43 assert self.dl_archive_path.is_file()
44 logger.info("Extracting %s to %s", self.dl_archive_path, extract_path)
45 with zipfile.ZipFile(self.dl_archive_path) as zf:
46 zf.extractall(extract_path)
47 assert self.gdk_extract_path.is_dir(), f"{self.gdk_extract_path} must exist"
48
49 def extract_development_kit(self) -> None:
50 extract_dks_cmd = self.gdk_extract_path / "SetupScripts/ExtractXboxOneDKs.cmd"
51 assert extract_dks_cmd.is_file()
52 logger.info("Extracting GDK Development Kit: running %s", extract_dks_cmd)
53 cmd = ["cmd.exe", "/C", str(extract_dks_cmd), str(self.gdk_extract_path), str(self.gdk_path)]
54 logger.debug("Running %r", cmd)
55 subprocess.check_call(cmd)
56
57 def detect_vs_version(self) -> str:
58 vs_regex = re.compile("VS([0-9]{4})")
59 supported_vs_versions = []
60 for p in self.gaming_grdk_build_path.iterdir():
61 if not p.is_dir():
62 continue
63 if m := vs_regex.match(p.name):
64 supported_vs_versions.append(m.group(1))
65 logger.info(f"Supported Visual Studio versions: {supported_vs_versions}")
66 vs_versions = set(self.vs_folder.parts).intersection(set(supported_vs_versions))
67 if not vs_versions:
68 raise RuntimeError("Visual Studio version is incompatible")
69 if len(vs_versions) > 1:
70 raise RuntimeError(f"Too many compatible VS versions found ({vs_versions})")
71 vs_version = vs_versions.pop()
72 logger.info(f"Used Visual Studio version: {vs_version}")
73 return vs_version
74
75 def detect_vs_toolset(self) -> str:
76 toolset_paths = []
77 for ts_path in self.gdk_toolset_parent_path.iterdir():
78 if not ts_path.is_dir():
79 continue
80 ms_props = ts_path / "Microsoft.Cpp.props"
81 if not ms_props.is_file():
82 continue
83 toolset_paths.append(ts_path.name)
84 logger.info("Detected Visual Studio toolsets: %s", toolset_paths)
85 assert toolset_paths, "Have we detected at least one toolset?"
86
87 def toolset_number(toolset: str) -> int:
88 if m:= re.match("[^0-9]*([0-9]+).*", toolset):
89 return int(m.group(1))
90 return -9
91
92 return max(toolset_paths, key=toolset_number)
93
94 @property
95 def vs_version(self) -> str:
96 if self._vs_version is None:
97 self._vs_version = self.detect_vs_version()
98 return self._vs_version
99
100 @property
101 def vs_toolset(self) -> str:
102 if self._vs_toolset is None:
103 self._vs_toolset = self.detect_vs_toolset()
104 return self._vs_toolset
105
106 @staticmethod
107 def copy_files_and_merge_into(srcdir: Path, dstdir: Path) -> None:
108 logger.info(f"Copy {srcdir} to {dstdir}")
109 for root, _, files in os.walk(srcdir):
110 dest_root = dstdir / Path(root).relative_to(srcdir)
111 if not dest_root.is_dir():
112 dest_root.mkdir()
113 for file in files:
114 srcfile = Path(root) / file
115 dstfile = dest_root / file
116 shutil.copy(srcfile, dstfile)
117
118 def copy_msbuild(self) -> None:
119 vc_toolset_parent_path = self.vs_folder / "MSBuild/Microsoft/VC"
120 if 1:
121 logger.info(f"Detected compatible Visual Studio version: {self.vs_version}")
122 srcdir = vc_toolset_parent_path
123 dstdir = self.gdk_toolset_parent_path
124 assert srcdir.is_dir(), "Source directory must exist"
125 assert dstdir.is_dir(), "Destination directory must exist"
126
127 self.copy_files_and_merge_into(srcdir=srcdir, dstdir=dstdir)
128
129 @property
130 def game_dk_path(self) -> Path:
131 return self.gdk_path / "Microsoft GDK"
132
133 @property
134 def game_dk_latest_path(self) -> Path:
135 return self.game_dk_path / self.gdk_edition
136
137 @property
138 def windows_sdk_path(self) -> Path:
139 return self.gdk_path / "Windows Kits/10"
140
141 @property
142 def gaming_grdk_build_path(self) -> Path:
143 return self.game_dk_latest_path / "GRDK"
144
145 @property
146 def gdk_toolset_parent_path(self) -> Path:
147 return self.gaming_grdk_build_path / f"VS{self.vs_version}/flatDeployment/MSBuild/Microsoft/VC"
148
149 @property
150 def env(self) -> dict[str, str]:
151 game_dk = self.game_dk_path
152 game_dk_latest = self.game_dk_latest_path
153 windows_sdk_dir = self.windows_sdk_path
154 gaming_grdk_build = self.gaming_grdk_build_path
155
156 return {
157 "GRDKEDITION": f"{self.gdk_edition}",
158 "GameDK": f"{game_dk}\\",
159 "GameDKLatest": f"{ game_dk_latest }\\",
160 "WindowsSdkDir": f"{ windows_sdk_dir }\\",
161 "GamingGRDKBuild": f"{ gaming_grdk_build }\\",
162 "VSInstallDir": f"{ self.vs_folder }\\",
163 }
164
165 def create_user_props(self, path: Path) -> None:
166 vc_targets_path = self.gaming_grdk_build_path / f"VS{ self.vs_version }/flatDeployment/MSBuild/Microsoft/VC/{ self.vs_toolset }"
167 vc_targets_path16 = self.gaming_grdk_build_path / f"VS2019/flatDeployment/MSBuild/Microsoft/VC/{ self.vs_toolset }"
168 vc_targets_path17 = self.gaming_grdk_build_path / f"VS2022/flatDeployment/MSBuild/Microsoft/VC/{ self.vs_toolset }"
169 additional_include_directories = ";".join(str(p) for p in self.gdk_include_paths)
170 additional_library_directories = ";".join(str(p) for p in self.gdk_library_paths)
171 durango_xdk_install_path = self.gdk_path / "Microsoft GDK"
172 with path.open("w") as f:
173 f.write(textwrap.dedent(f"""\
174 <?xml version="1.0" encoding="utf-8"?>
175 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
176 <PropertyGroup>
177 <VCTargetsPath>{ vc_targets_path }\\</VCTargetsPath>
178 <VCTargetsPath16>{ vc_targets_path16 }\\</VCTargetsPath16>
179 <VCTargetsPath17>{ vc_targets_path17 }\\</VCTargetsPath17>
180 <BWOI_GDK_Path>{ self.gaming_grdk_build_path }\\</BWOI_GDK_Path>
181 <Platform Condition="'$(Platform)' == ''">Gaming.Desktop.x64</Platform>
182 <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
183 <XdkEditionTarget>{ self.gdk_edition }</XdkEditionTarget>
184 <DurangoXdkInstallPath>{ durango_xdk_install_path }</DurangoXdkInstallPath>
185
186 <DefaultXdkEditionRootVS2019>$(DurangoXdkInstallPath)\\{self.gdk_edition}\\GRDK\\VS2019\\flatDeployment\\MSBuild\\Microsoft\\VC\\{self.vs_toolset}\\Platforms\\$(Platform)\\</DefaultXdkEditionRootVS2019>
187 <XdkEditionRootVS2019>$(DurangoXdkInstallPath)\\{self.gdk_edition}\\GRDK\\VS2019\\flatDeployment\\MSBuild\\Microsoft\\VC\\{self.vs_toolset}\\Platforms\\$(Platform)\\</XdkEditionRootVS2019>
188 <DefaultXdkEditionRootVS2022>$(DurangoXdkInstallPath)\\{self.gdk_edition}\\GRDK\\VS2022\\flatDeployment\\MSBuild\\Microsoft\\VC\\{self.vs_toolset}\\Platforms\\$(Platform)\\</DefaultXdkEditionRootVS2022>
189 <XdkEditionRootVS2022>$(DurangoXdkInstallPath)\\{self.gdk_edition}\\GRDK\\VS2022\\flatDeployment\\MSBuild\\Microsoft\\VC\\{self.vs_toolset}\\Platforms\\$(Platform)\\</XdkEditionRootVS2022>
190
191 <Deterministic>true</Deterministic>
192 <DisableInstalledVCTargetsUse>true</DisableInstalledVCTargetsUse>
193 <ClearDevCommandPromptEnvVars>true</ClearDevCommandPromptEnvVars>
194 </PropertyGroup>
195 <ItemDefinitionGroup Condition="'$(Platform)' == 'Gaming.Desktop.x64'">
196 <ClCompile>
197 <AdditionalIncludeDirectories>{ additional_include_directories };%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
198 </ClCompile>
199 <Link>
200 <AdditionalLibraryDirectories>{ additional_library_directories };%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
201 </Link>
202 </ItemDefinitionGroup>
203 </Project>
204 """))
205
206 @property
207 def gdk_include_paths(self) -> list[Path]:
208 return [
209 self.gaming_grdk_build_path / "gamekit/include",
210 ]
211
212 @property
213 def gdk_library_paths(self) -> list[Path]:
214 return [
215 self.gaming_grdk_build_path / f"gamekit/lib/{self.arch}",
216 ]
217
218 @property
219 def gdk_binary_path(self) -> list[Path]:
220 return [
221 self.gaming_grdk_build_path / "bin",
222 self.game_dk_path / "bin",
223 ]
224
225 @property
226 def build_env(self) -> dict[str, str]:
227 gdk_include = ";".join(str(p) for p in self.gdk_include_paths)
228 gdk_lib = ";".join(str(p) for p in self.gdk_library_paths)
229 gdk_path = ";".join(str(p) for p in self.gdk_binary_path)
230 return {
231 "GDK_INCLUDE": gdk_include,
232 "GDK_LIB": gdk_lib,
233 "GDK_PATH": gdk_path,
234 }
235
236 def print_env(self) -> None:
237 for k, v in self.env.items():
238 print(f"set \"{k}={v}\"")
239 print()
240 for k, v in self.build_env.items():
241 print(f"set \"{k}={v}\"")
242 print()
243 print(f"set \"PATH=%GDK_PATH%;%PATH%\"")
244 print(f"set \"LIB=%GDK_LIB%;%LIB%\"")
245 print(f"set \"INCLUDE=%GDK_INCLUDE%;%INCLUDE%\"")
246
247
248def main():
249 logging.basicConfig(level=logging.INFO)
250 parser = argparse.ArgumentParser(allow_abbrev=False)
251 parser.add_argument("--arch", choices=["amd64"], default="amd64", help="Architecture")
252 parser.add_argument("--download", action="store_true", help="Download GDK")
253 parser.add_argument("--extract", action="store_true", help="Extract downloaded GDK")
254 parser.add_argument("--copy-msbuild", action="store_true", help="Copy MSBuild files")
255 parser.add_argument("--temp-folder", help="Temporary folder where to download and extract GDK")
256 parser.add_argument("--gdk-path", required=True, type=Path, help="Folder where to store the GDK")
257 parser.add_argument("--ref-edition", type=str, help="Git ref and GDK edition separated by comma")
258 parser.add_argument("--vs-folder", required=True, type=Path, help="Installation folder of Visual Studio")
259 parser.add_argument("--vs-version", required=False, type=int, help="Visual Studio version")
260 parser.add_argument("--vs-toolset", required=False, help="Visual Studio toolset (e.g. v150)")
261 parser.add_argument("--props-folder", required=False, type=Path, default=Path(), help="Visual Studio toolset (e.g. v150)")
262 parser.add_argument("--no-user-props", required=False, dest="user_props", action="store_false", help="Don't ")
263 args = parser.parse_args()
264
265 logging.basicConfig(level=logging.INFO)
266
267 git_ref = None
268 gdk_edition = None
269 if args.ref_edition is not None:
270 git_ref, gdk_edition = args.ref_edition.split(",", 1)
271 try:
272 int(gdk_edition)
273 except ValueError:
274 parser.error("Edition should be an integer (YYMMUU) (Y=year M=month U=update)")
275
276 configurator = GdDesktopConfigurator(
277 arch=args.arch,
278 git_ref=git_ref,
279 gdk_edition=gdk_edition,
280 vs_folder=args.vs_folder,
281 vs_version=args.vs_version,
282 vs_toolset=args.vs_toolset,
283 gdk_path=args.gdk_path,
284 temp_folder=args.temp_folder,
285 )
286
287 if args.download:
288 configurator.download_archive()
289
290 if args.extract:
291 configurator.extract_zip_archive()
292
293 configurator.extract_development_kit()
294
295 if args.copy_msbuild:
296 configurator.copy_msbuild()
297
298 if args.user_props:
299 configurator.print_env()
300 configurator.create_user_props(args.props_folder / "Directory.Build.props")
301
302if __name__ == "__main__":
303 raise SystemExit(main())