1*cf78ab8cSAndroid Build Coastguard Worker# Copyright 2024 - The Android Open Source Project 2*cf78ab8cSAndroid Build Coastguard Worker# 3*cf78ab8cSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the', help='License'); 4*cf78ab8cSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 5*cf78ab8cSAndroid Build Coastguard Worker# You may obtain a copy of the License at 6*cf78ab8cSAndroid Build Coastguard Worker# 7*cf78ab8cSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 8*cf78ab8cSAndroid Build Coastguard Worker# 9*cf78ab8cSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 10*cf78ab8cSAndroid Build Coastguard Worker# distributed under the License is distributed on an', help='AS IS' BASIS, 11*cf78ab8cSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*cf78ab8cSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 13*cf78ab8cSAndroid Build Coastguard Worker# limitations under the License. 14*cf78ab8cSAndroid Build Coastguard Workerfrom collections import UserDict 15*cf78ab8cSAndroid Build Coastguard Workerimport json 16*cf78ab8cSAndroid Build Coastguard Workerimport logging 17*cf78ab8cSAndroid Build Coastguard Workerimport os 18*cf78ab8cSAndroid Build Coastguard Workerfrom pathlib import Path 19*cf78ab8cSAndroid Build Coastguard Workerimport platform 20*cf78ab8cSAndroid Build Coastguard Workerimport subprocess 21*cf78ab8cSAndroid Build Coastguard Workerfrom utils import rust_version 22*cf78ab8cSAndroid Build Coastguard Worker 23*cf78ab8cSAndroid Build Coastguard Worker 24*cf78ab8cSAndroid Build Coastguard Workerclass BaseEnvironment(UserDict): 25*cf78ab8cSAndroid Build Coastguard Worker """Base class for environment management, providing a common foundation for 26*cf78ab8cSAndroid Build Coastguard Worker 27*cf78ab8cSAndroid Build Coastguard Worker both Posix and Windows environments. 28*cf78ab8cSAndroid Build Coastguard Worker """ 29*cf78ab8cSAndroid Build Coastguard Worker 30*cf78ab8cSAndroid Build Coastguard Worker def __init__(self, aosp: Path): 31*cf78ab8cSAndroid Build Coastguard Worker paths = [ 32*cf78ab8cSAndroid Build Coastguard Worker str( 33*cf78ab8cSAndroid Build Coastguard Worker aosp 34*cf78ab8cSAndroid Build Coastguard Worker / "external" 35*cf78ab8cSAndroid Build Coastguard Worker / "qemu" 36*cf78ab8cSAndroid Build Coastguard Worker / "android" 37*cf78ab8cSAndroid Build Coastguard Worker / "third_party" 38*cf78ab8cSAndroid Build Coastguard Worker / "chromium" 39*cf78ab8cSAndroid Build Coastguard Worker / "depot_tools" 40*cf78ab8cSAndroid Build Coastguard Worker ) 41*cf78ab8cSAndroid Build Coastguard Worker ] 42*cf78ab8cSAndroid Build Coastguard Worker 43*cf78ab8cSAndroid Build Coastguard Worker # Append prebuilt rust toolchain except for darwin_aarch64 44*cf78ab8cSAndroid Build Coastguard Worker # TODO(360874898): aarch64-apple-darwin prebuilt rust toolchain supported from 1.77.1 45*cf78ab8cSAndroid Build Coastguard Worker if not (platform.system() == "Darwin" and platform.machine() == "arm64"): 46*cf78ab8cSAndroid Build Coastguard Worker paths.append( 47*cf78ab8cSAndroid Build Coastguard Worker str( 48*cf78ab8cSAndroid Build Coastguard Worker aosp 49*cf78ab8cSAndroid Build Coastguard Worker / "prebuilts" 50*cf78ab8cSAndroid Build Coastguard Worker / "rust" 51*cf78ab8cSAndroid Build Coastguard Worker / f"{platform.system().lower()}-x86" 52*cf78ab8cSAndroid Build Coastguard Worker / f"{rust_version()}" 53*cf78ab8cSAndroid Build Coastguard Worker / "bin" 54*cf78ab8cSAndroid Build Coastguard Worker ) 55*cf78ab8cSAndroid Build Coastguard Worker ) 56*cf78ab8cSAndroid Build Coastguard Worker 57*cf78ab8cSAndroid Build Coastguard Worker paths.append(os.environ.get("PATH", "")) 58*cf78ab8cSAndroid Build Coastguard Worker 59*cf78ab8cSAndroid Build Coastguard Worker super().__init__({"PATH": os.pathsep.join(paths)}) 60*cf78ab8cSAndroid Build Coastguard Worker 61*cf78ab8cSAndroid Build Coastguard Worker 62*cf78ab8cSAndroid Build Coastguard Workerclass PosixEnvironment(BaseEnvironment): 63*cf78ab8cSAndroid Build Coastguard Worker 64*cf78ab8cSAndroid Build Coastguard Worker def __init__(self, aosp: Path): 65*cf78ab8cSAndroid Build Coastguard Worker super().__init__(aosp) 66*cf78ab8cSAndroid Build Coastguard Worker 67*cf78ab8cSAndroid Build Coastguard Worker 68*cf78ab8cSAndroid Build Coastguard Workerclass VisualStudioNotFoundException(Exception): 69*cf78ab8cSAndroid Build Coastguard Worker pass 70*cf78ab8cSAndroid Build Coastguard Worker 71*cf78ab8cSAndroid Build Coastguard Worker 72*cf78ab8cSAndroid Build Coastguard Workerclass VisualStudioMissingVarException(Exception): 73*cf78ab8cSAndroid Build Coastguard Worker pass 74*cf78ab8cSAndroid Build Coastguard Worker 75*cf78ab8cSAndroid Build Coastguard Worker 76*cf78ab8cSAndroid Build Coastguard Workerclass VisualStudioNativeWorkloadNotFoundException(Exception): 77*cf78ab8cSAndroid Build Coastguard Worker pass 78*cf78ab8cSAndroid Build Coastguard Worker 79*cf78ab8cSAndroid Build Coastguard Worker 80*cf78ab8cSAndroid Build Coastguard Workerclass WindowsEnvironment(BaseEnvironment): 81*cf78ab8cSAndroid Build Coastguard Worker """Environment manager for Windows systems, specifically handling Visual Studio integration.""" 82*cf78ab8cSAndroid Build Coastguard Worker 83*cf78ab8cSAndroid Build Coastguard Worker def __init__(self, aosp: Path): 84*cf78ab8cSAndroid Build Coastguard Worker assert platform.system() == "Windows" 85*cf78ab8cSAndroid Build Coastguard Worker super().__init__(aosp) 86*cf78ab8cSAndroid Build Coastguard Worker for key in os.environ: 87*cf78ab8cSAndroid Build Coastguard Worker self[key.upper()] = os.environ[key] 88*cf78ab8cSAndroid Build Coastguard Worker 89*cf78ab8cSAndroid Build Coastguard Worker vs = self._visual_studio() 90*cf78ab8cSAndroid Build Coastguard Worker logging.info("Loading environment from %s", vs) 91*cf78ab8cSAndroid Build Coastguard Worker env_lines = subprocess.check_output( 92*cf78ab8cSAndroid Build Coastguard Worker [vs, "&&", "set"], encoding="utf-8" 93*cf78ab8cSAndroid Build Coastguard Worker ).splitlines() 94*cf78ab8cSAndroid Build Coastguard Worker for line in env_lines: 95*cf78ab8cSAndroid Build Coastguard Worker if "=" in line: 96*cf78ab8cSAndroid Build Coastguard Worker key, val = line.split("=", 1) 97*cf78ab8cSAndroid Build Coastguard Worker # Variables in windows are case insensitive, but not in python dict! 98*cf78ab8cSAndroid Build Coastguard Worker self[key.upper()] = val 99*cf78ab8cSAndroid Build Coastguard Worker 100*cf78ab8cSAndroid Build Coastguard Worker # Set PYTHONUTF8 to 1 101*cf78ab8cSAndroid Build Coastguard Worker self["PYTHONUTF8"] = "1" 102*cf78ab8cSAndroid Build Coastguard Worker 103*cf78ab8cSAndroid Build Coastguard Worker if not "VSINSTALLDIR" in self: 104*cf78ab8cSAndroid Build Coastguard Worker raise VisualStudioMissingVarException( 105*cf78ab8cSAndroid Build Coastguard Worker "Missing VSINSTALLDIR in environment" 106*cf78ab8cSAndroid Build Coastguard Worker ) 107*cf78ab8cSAndroid Build Coastguard Worker 108*cf78ab8cSAndroid Build Coastguard Worker if not "VCTOOLSINSTALLDIR" in self: 109*cf78ab8cSAndroid Build Coastguard Worker raise VisualStudioMissingVarException( 110*cf78ab8cSAndroid Build Coastguard Worker "Missing VCTOOLSINSTALLDIR in environment" 111*cf78ab8cSAndroid Build Coastguard Worker ) 112*cf78ab8cSAndroid Build Coastguard Worker 113*cf78ab8cSAndroid Build Coastguard Worker def _visual_studio(self) -> Path: 114*cf78ab8cSAndroid Build Coastguard Worker """Locates the Visual Studio installation and its Native Desktop workload. 115*cf78ab8cSAndroid Build Coastguard Worker 116*cf78ab8cSAndroid Build Coastguard Worker Raises: 117*cf78ab8cSAndroid Build Coastguard Worker VisualStudioNotFoundException: When Visual Studio is not found. 118*cf78ab8cSAndroid Build Coastguard Worker VisualStudioNativeWorkloadNotFoundException: When the Native Desktop 119*cf78ab8cSAndroid Build Coastguard Worker workload is not found. 120*cf78ab8cSAndroid Build Coastguard Worker 121*cf78ab8cSAndroid Build Coastguard Worker Returns: 122*cf78ab8cSAndroid Build Coastguard Worker Path: Path to the Visual Studio vcvars64.bat file. 123*cf78ab8cSAndroid Build Coastguard Worker """ 124*cf78ab8cSAndroid Build Coastguard Worker prgrfiles = Path(os.getenv("ProgramFiles(x86)", "C:\Program Files (x86)")) 125*cf78ab8cSAndroid Build Coastguard Worker res = subprocess.check_output([ 126*cf78ab8cSAndroid Build Coastguard Worker str( 127*cf78ab8cSAndroid Build Coastguard Worker prgrfiles / "Microsoft Visual Studio" / "Installer" / "vswhere.exe" 128*cf78ab8cSAndroid Build Coastguard Worker ), 129*cf78ab8cSAndroid Build Coastguard Worker "-requires", 130*cf78ab8cSAndroid Build Coastguard Worker "Microsoft.VisualStudio.Workload.NativeDesktop", 131*cf78ab8cSAndroid Build Coastguard Worker "-sort", 132*cf78ab8cSAndroid Build Coastguard Worker "-format", 133*cf78ab8cSAndroid Build Coastguard Worker "json", 134*cf78ab8cSAndroid Build Coastguard Worker "-utf8", 135*cf78ab8cSAndroid Build Coastguard Worker ]) 136*cf78ab8cSAndroid Build Coastguard Worker vsresult = json.loads(res) 137*cf78ab8cSAndroid Build Coastguard Worker if len(vsresult) == 0: 138*cf78ab8cSAndroid Build Coastguard Worker raise VisualStudioNativeWorkloadNotFoundException( 139*cf78ab8cSAndroid Build Coastguard Worker "No visual studio with the native desktop load available." 140*cf78ab8cSAndroid Build Coastguard Worker ) 141*cf78ab8cSAndroid Build Coastguard Worker 142*cf78ab8cSAndroid Build Coastguard Worker for install in vsresult: 143*cf78ab8cSAndroid Build Coastguard Worker logging.debug("Considering %s", install["displayName"]) 144*cf78ab8cSAndroid Build Coastguard Worker candidates = list( 145*cf78ab8cSAndroid Build Coastguard Worker Path(install["installationPath"]).glob("**/vcvars64.bat") 146*cf78ab8cSAndroid Build Coastguard Worker ) 147*cf78ab8cSAndroid Build Coastguard Worker 148*cf78ab8cSAndroid Build Coastguard Worker if len(candidates) > 0: 149*cf78ab8cSAndroid Build Coastguard Worker return candidates[0].absolute() 150*cf78ab8cSAndroid Build Coastguard Worker 151*cf78ab8cSAndroid Build Coastguard Worker # Oh oh, no visual studio.. 152*cf78ab8cSAndroid Build Coastguard Worker raise VisualStudioNotFoundException( 153*cf78ab8cSAndroid Build Coastguard Worker "Unable to detect a visual studio installation with the native desktop" 154*cf78ab8cSAndroid Build Coastguard Worker " workload." 155*cf78ab8cSAndroid Build Coastguard Worker ) 156*cf78ab8cSAndroid Build Coastguard Worker 157*cf78ab8cSAndroid Build Coastguard Worker 158*cf78ab8cSAndroid Build Coastguard Workerdef get_default_environment(aosp: Path): 159*cf78ab8cSAndroid Build Coastguard Worker """Returns the appropriate environment manager based on the current operating system. 160*cf78ab8cSAndroid Build Coastguard Worker 161*cf78ab8cSAndroid Build Coastguard Worker The environment will make sure the following things hold: 162*cf78ab8cSAndroid Build Coastguard Worker 163*cf78ab8cSAndroid Build Coastguard Worker - Ninja will be on the PATH 164*cf78ab8cSAndroid Build Coastguard Worker - The visual studio tools environment will be loaded 165*cf78ab8cSAndroid Build Coastguard Worker """ 166*cf78ab8cSAndroid Build Coastguard Worker if platform.system() == "Windows": 167*cf78ab8cSAndroid Build Coastguard Worker return WindowsEnvironment(aosp) 168*cf78ab8cSAndroid Build Coastguard Worker return PosixEnvironment(aosp) 169