1*8975f5c5SAndroid Build Coastguard Worker#!/usr/bin/python3 2*8975f5c5SAndroid Build Coastguard Worker# 3*8975f5c5SAndroid Build Coastguard Worker# Copyright 2024 The ANGLE Project Authors. All rights reserved. 4*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 5*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file. 6*8975f5c5SAndroid Build Coastguard Worker# 7*8975f5c5SAndroid Build Coastguard Worker# winappsdk_setup.py: 8*8975f5c5SAndroid Build Coastguard Worker# Downloads and processes a specific version of Windows App SDK 9*8975f5c5SAndroid Build Coastguard Worker# for use when building ANGLE for WinUI 3 apps. 10*8975f5c5SAndroid Build Coastguard Worker# 11*8975f5c5SAndroid Build Coastguard Worker# Usage: 12*8975f5c5SAndroid Build Coastguard Worker# python3 winappsdk_setup.py [--version <package-version>] [--output /path/to/dest] [--force] 13*8975f5c5SAndroid Build Coastguard Worker 14*8975f5c5SAndroid Build Coastguard Workerimport argparse 15*8975f5c5SAndroid Build Coastguard Workerimport fnmatch 16*8975f5c5SAndroid Build Coastguard Workerimport io 17*8975f5c5SAndroid Build Coastguard Workerimport os 18*8975f5c5SAndroid Build Coastguard Workerimport subprocess 19*8975f5c5SAndroid Build Coastguard Workerimport urllib.request 20*8975f5c5SAndroid Build Coastguard Workerimport zipfile 21*8975f5c5SAndroid Build Coastguard Worker 22*8975f5c5SAndroid Build Coastguard Workerpackage_id = "Microsoft.WindowsAppSDK" 23*8975f5c5SAndroid Build Coastguard Workeruap_version = "10.0.18362" 24*8975f5c5SAndroid Build Coastguard Worker 25*8975f5c5SAndroid Build Coastguard Workerdefault_version = "1.3.230724000" 26*8975f5c5SAndroid Build Coastguard Workerdefault_output = "third_party\WindowsAppSDK" 27*8975f5c5SAndroid Build Coastguard Worker 28*8975f5c5SAndroid Build Coastguard Worker 29*8975f5c5SAndroid Build Coastguard Workerdef download_and_extract_nuget_package(force, version, output_path): 30*8975f5c5SAndroid Build Coastguard Worker # first check if the last download was successful 31*8975f5c5SAndroid Build Coastguard Worker stamp = os.path.join(output_path, f"{version}.stamp") 32*8975f5c5SAndroid Build Coastguard Worker if os.path.exists(stamp) and not force: 33*8975f5c5SAndroid Build Coastguard Worker return 34*8975f5c5SAndroid Build Coastguard Worker 35*8975f5c5SAndroid Build Coastguard Worker # download the package 36*8975f5c5SAndroid Build Coastguard Worker nuget_url = f"https://www.nuget.org/api/v2/package/{package_id}/{version}" 37*8975f5c5SAndroid Build Coastguard Worker with urllib.request.urlopen(nuget_url) as response: 38*8975f5c5SAndroid Build Coastguard Worker if response.status == 200: 39*8975f5c5SAndroid Build Coastguard Worker package_bytes = io.BytesIO(response.read()) 40*8975f5c5SAndroid Build Coastguard Worker # extract 41*8975f5c5SAndroid Build Coastguard Worker os.makedirs(output_path, exist_ok=True) 42*8975f5c5SAndroid Build Coastguard Worker with zipfile.ZipFile(package_bytes, 'r') as zip_ref: 43*8975f5c5SAndroid Build Coastguard Worker zip_ref.extractall(output_path) 44*8975f5c5SAndroid Build Coastguard Worker # make a stamp to avoid re-downloading 45*8975f5c5SAndroid Build Coastguard Worker with open(stamp, 'w') as file: 46*8975f5c5SAndroid Build Coastguard Worker pass 47*8975f5c5SAndroid Build Coastguard Worker else: 48*8975f5c5SAndroid Build Coastguard Worker print( 49*8975f5c5SAndroid Build Coastguard Worker f"Failed to download the {package_id} NuGet package. Status code: {response.status}" 50*8975f5c5SAndroid Build Coastguard Worker ) 51*8975f5c5SAndroid Build Coastguard Worker sys.exit(1) 52*8975f5c5SAndroid Build Coastguard Worker 53*8975f5c5SAndroid Build Coastguard Worker 54*8975f5c5SAndroid Build Coastguard Workerdef get_win_sdk(): 55*8975f5c5SAndroid Build Coastguard Worker p = os.getenv("ProgramFiles(x86)", "C:\\Program Files (x86)") 56*8975f5c5SAndroid Build Coastguard Worker win_sdk = os.getenv("WindowsSdkDir") 57*8975f5c5SAndroid Build Coastguard Worker if not win_sdk: 58*8975f5c5SAndroid Build Coastguard Worker win_sdk = os.path.join(p, "Windows Kits", "10") 59*8975f5c5SAndroid Build Coastguard Worker print("%WindowsSdkDir% not set. Defaulting to", win_sdk) 60*8975f5c5SAndroid Build Coastguard Worker print("You might want to run this from a Visual Studio cmd prompt.") 61*8975f5c5SAndroid Build Coastguard Worker return win_sdk 62*8975f5c5SAndroid Build Coastguard Worker 63*8975f5c5SAndroid Build Coastguard Worker 64*8975f5c5SAndroid Build Coastguard Workerdef get_latest_sdk_version(win_sdk): 65*8975f5c5SAndroid Build Coastguard Worker files = os.listdir(os.path.join(win_sdk, "bin")) 66*8975f5c5SAndroid Build Coastguard Worker filtered_files = fnmatch.filter(files, "10.0.*") 67*8975f5c5SAndroid Build Coastguard Worker sorted_files = sorted(filtered_files, reverse=True) 68*8975f5c5SAndroid Build Coastguard Worker return sorted_files[0] 69*8975f5c5SAndroid Build Coastguard Worker 70*8975f5c5SAndroid Build Coastguard Worker 71*8975f5c5SAndroid Build Coastguard Workerdef run_winmdidl(force, win_sdk_bin, output_path, winmd, stamp_filename=None): 72*8975f5c5SAndroid Build Coastguard Worker include = os.path.join(output_path, "include") 73*8975f5c5SAndroid Build Coastguard Worker lib = os.path.join(output_path, "lib") 74*8975f5c5SAndroid Build Coastguard Worker 75*8975f5c5SAndroid Build Coastguard Worker if stamp_filename: 76*8975f5c5SAndroid Build Coastguard Worker stamp = os.path.join(include, stamp_filename) 77*8975f5c5SAndroid Build Coastguard Worker else: 78*8975f5c5SAndroid Build Coastguard Worker no_ext = os.path.splitext(os.path.basename(winmd))[0] 79*8975f5c5SAndroid Build Coastguard Worker stamp = os.path.join(include, no_ext + ".idl") 80*8975f5c5SAndroid Build Coastguard Worker if os.path.exists(stamp) and not force: 81*8975f5c5SAndroid Build Coastguard Worker return 82*8975f5c5SAndroid Build Coastguard Worker 83*8975f5c5SAndroid Build Coastguard Worker winmdidl = os.path.join(win_sdk_bin, "winmdidl.exe") 84*8975f5c5SAndroid Build Coastguard Worker command = [ 85*8975f5c5SAndroid Build Coastguard Worker winmdidl, 86*8975f5c5SAndroid Build Coastguard Worker os.path.join(lib, winmd), "/metadata_dir:C:\\Windows\\System32\\WinMetadata", 87*8975f5c5SAndroid Build Coastguard Worker "/metadata_dir:" + os.path.join(lib, f"uap{uap_version}"), 88*8975f5c5SAndroid Build Coastguard Worker "/metadata_dir:" + os.path.join(lib, "uap10.0"), "/outdir:" + include, "/nologo" 89*8975f5c5SAndroid Build Coastguard Worker ] 90*8975f5c5SAndroid Build Coastguard Worker subprocess.run(command, check=True, cwd=include) 91*8975f5c5SAndroid Build Coastguard Worker 92*8975f5c5SAndroid Build Coastguard Worker 93*8975f5c5SAndroid Build Coastguard Workerdef run_midlrt(force, win_sdk_bin, output_path, idl): 94*8975f5c5SAndroid Build Coastguard Worker include = os.path.join(output_path, "include") 95*8975f5c5SAndroid Build Coastguard Worker lib = os.path.join(output_path, "lib") 96*8975f5c5SAndroid Build Coastguard Worker 97*8975f5c5SAndroid Build Coastguard Worker no_ext = os.path.splitext(os.path.basename(idl))[0] 98*8975f5c5SAndroid Build Coastguard Worker stamp = os.path.join(include, no_ext + ".h") 99*8975f5c5SAndroid Build Coastguard Worker if os.path.exists(stamp) and not force: 100*8975f5c5SAndroid Build Coastguard Worker return 101*8975f5c5SAndroid Build Coastguard Worker 102*8975f5c5SAndroid Build Coastguard Worker midlrt = os.path.join(win_sdk_bin, "midlrt.exe") 103*8975f5c5SAndroid Build Coastguard Worker command = [ 104*8975f5c5SAndroid Build Coastguard Worker midlrt, 105*8975f5c5SAndroid Build Coastguard Worker os.path.join(include, idl), "/metadata_dir", "C:\\Windows\\System32\\WinMetadata", 106*8975f5c5SAndroid Build Coastguard Worker "/ns_prefix", "/nomidl", "/nologo" 107*8975f5c5SAndroid Build Coastguard Worker ] 108*8975f5c5SAndroid Build Coastguard Worker subprocess.run(command, check=True, cwd=include) 109*8975f5c5SAndroid Build Coastguard Worker 110*8975f5c5SAndroid Build Coastguard Worker 111*8975f5c5SAndroid Build Coastguard Workerif __name__ == "__main__": 112*8975f5c5SAndroid Build Coastguard Worker 113*8975f5c5SAndroid Build Coastguard Worker parser = argparse.ArgumentParser(description="Setup the Windows App SDK.") 114*8975f5c5SAndroid Build Coastguard Worker parser.add_argument( 115*8975f5c5SAndroid Build Coastguard Worker "--version", default=default_version, help="the package version to download") 116*8975f5c5SAndroid Build Coastguard Worker parser.add_argument( 117*8975f5c5SAndroid Build Coastguard Worker "--output", default=default_output, help="the destination path for extracted contents") 118*8975f5c5SAndroid Build Coastguard Worker parser.add_argument( 119*8975f5c5SAndroid Build Coastguard Worker "--force", action="store_true", help="ignore existing files and re-download") 120*8975f5c5SAndroid Build Coastguard Worker args = parser.parse_args() 121*8975f5c5SAndroid Build Coastguard Worker 122*8975f5c5SAndroid Build Coastguard Worker if os.path.isabs(args.output): 123*8975f5c5SAndroid Build Coastguard Worker output_path = args.output 124*8975f5c5SAndroid Build Coastguard Worker else: 125*8975f5c5SAndroid Build Coastguard Worker output_path = os.path.join(os.getcwd(), args.output) 126*8975f5c5SAndroid Build Coastguard Worker 127*8975f5c5SAndroid Build Coastguard Worker win_sdk = get_win_sdk() 128*8975f5c5SAndroid Build Coastguard Worker latest_sdk = get_latest_sdk_version(win_sdk) 129*8975f5c5SAndroid Build Coastguard Worker arch = "x64" 130*8975f5c5SAndroid Build Coastguard Worker win_sdk_bin = os.path.join(win_sdk, "bin", latest_sdk, arch) 131*8975f5c5SAndroid Build Coastguard Worker 132*8975f5c5SAndroid Build Coastguard Worker winmd_files = { 133*8975f5c5SAndroid Build Coastguard Worker f"uap{uap_version}\\Microsoft.Foundation.winmd": None, 134*8975f5c5SAndroid Build Coastguard Worker f"uap{uap_version}\\Microsoft.Graphics.winmd": "Microsoft.Graphics.DirectX.idl", 135*8975f5c5SAndroid Build Coastguard Worker f"uap{uap_version}\\Microsoft.UI.winmd": None, 136*8975f5c5SAndroid Build Coastguard Worker "uap10.0\\Microsoft.UI.Text.winmd": None, 137*8975f5c5SAndroid Build Coastguard Worker "uap10.0\\Microsoft.UI.Xaml.winmd": None, 138*8975f5c5SAndroid Build Coastguard Worker "uap10.0\\Microsoft.Web.WebView2.Core.winmd": None, 139*8975f5c5SAndroid Build Coastguard Worker } 140*8975f5c5SAndroid Build Coastguard Worker 141*8975f5c5SAndroid Build Coastguard Worker idl_files = [ 142*8975f5c5SAndroid Build Coastguard Worker "Microsoft.Foundation.idl", 143*8975f5c5SAndroid Build Coastguard Worker "Microsoft.Graphics.DirectX.idl", 144*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Composition.idl", 145*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Composition.SystemBackdrops.idl", 146*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Dispatching.idl", 147*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.idl", 148*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Input.idl", 149*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Text.idl", 150*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Windowing.idl", 151*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Xaml.Automation.idl", 152*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Xaml.Automation.Peers.idl", 153*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Xaml.Automation.Provider.idl", 154*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Xaml.Automation.Text.idl", 155*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Xaml.Controls.idl", 156*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Xaml.Controls.Primitives.idl", 157*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Xaml.Data.idl", 158*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Xaml.Documents.idl", 159*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Xaml.idl", 160*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Xaml.Input.idl", 161*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Xaml.Interop.idl", 162*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Xaml.Media.Animation.idl", 163*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Xaml.Media.idl", 164*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Xaml.Media.Imaging.idl", 165*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Xaml.Media.Media3D.idl", 166*8975f5c5SAndroid Build Coastguard Worker "Microsoft.UI.Xaml.Navigation.idl", 167*8975f5c5SAndroid Build Coastguard Worker "Microsoft.Web.WebView2.Core.idl", 168*8975f5c5SAndroid Build Coastguard Worker ] 169*8975f5c5SAndroid Build Coastguard Worker 170*8975f5c5SAndroid Build Coastguard Worker progress = 1 171*8975f5c5SAndroid Build Coastguard Worker total = len(winmd_files) + len(idl_files) + 1 172*8975f5c5SAndroid Build Coastguard Worker 173*8975f5c5SAndroid Build Coastguard Worker # Download the NuGet package that contains all the files we need 174*8975f5c5SAndroid Build Coastguard Worker print( 175*8975f5c5SAndroid Build Coastguard Worker f"[{progress}/{total}] Downloading {package_id} NuGet package version {args.version} to {output_path}..." 176*8975f5c5SAndroid Build Coastguard Worker ) 177*8975f5c5SAndroid Build Coastguard Worker download_and_extract_nuget_package(args.force, args.version, output_path) 178*8975f5c5SAndroid Build Coastguard Worker 179*8975f5c5SAndroid Build Coastguard Worker # Generate .idl files from the .winmd files 180*8975f5c5SAndroid Build Coastguard Worker for winmd, header in winmd_files.items(): 181*8975f5c5SAndroid Build Coastguard Worker progress += 1 182*8975f5c5SAndroid Build Coastguard Worker print(f"[{progress}/{total}] Processing WINMD {winmd}...") 183*8975f5c5SAndroid Build Coastguard Worker run_winmdidl(args.force, win_sdk_bin, output_path, winmd, header) 184*8975f5c5SAndroid Build Coastguard Worker 185*8975f5c5SAndroid Build Coastguard Worker # Generate all the C++ headers and related files from the .idl files 186*8975f5c5SAndroid Build Coastguard Worker for idl in idl_files: 187*8975f5c5SAndroid Build Coastguard Worker progress += 1 188*8975f5c5SAndroid Build Coastguard Worker print(f"[{progress}/{total}] Processing IDL {idl}...") 189*8975f5c5SAndroid Build Coastguard Worker run_midlrt(args.force, win_sdk_bin, output_path, idl) 190*8975f5c5SAndroid Build Coastguard Worker 191*8975f5c5SAndroid Build Coastguard Worker print("Setup is complete.") 192*8975f5c5SAndroid Build Coastguard Worker print("") 193*8975f5c5SAndroid Build Coastguard Worker print(f"Pass winappsdk_dir=\"{output_path}\" to gn gen or ninja.") 194