1# This Source Code Form is subject to the terms of the Mozilla Public 2# License, v. 2.0. If a copy of the MPL was not distributed with this 3# file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 5from __future__ import absolute_import, print_function, unicode_literals 6 7import ctypes 8import os 9import sys 10import subprocess 11 12from mozboot.base import BaseBootstrapper 13 14 15def is_aarch64_host(): 16 from ctypes import wintypes 17 18 kernel32 = ctypes.windll.kernel32 19 IMAGE_FILE_MACHINE_UNKNOWN = 0 20 IMAGE_FILE_MACHINE_ARM64 = 0xAA64 21 22 try: 23 iswow64process2 = kernel32.IsWow64Process2 24 except Exception: 25 # If we can't access the symbol, we know we're not on aarch64. 26 return False 27 28 currentProcess = kernel32.GetCurrentProcess() 29 processMachine = wintypes.USHORT(IMAGE_FILE_MACHINE_UNKNOWN) 30 nativeMachine = wintypes.USHORT(IMAGE_FILE_MACHINE_UNKNOWN) 31 32 gotValue = iswow64process2( 33 currentProcess, ctypes.byref(processMachine), ctypes.byref(nativeMachine) 34 ) 35 # If this call fails, we have no idea. 36 if not gotValue: 37 return False 38 39 return nativeMachine.value == IMAGE_FILE_MACHINE_ARM64 40 41 42def get_is_windefender_disabled(): 43 import winreg 44 45 try: 46 with winreg.OpenKeyEx( 47 winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows Defender" 48 ) as windefender_key: 49 is_antivirus_disabled, _ = winreg.QueryValueEx( 50 windefender_key, "DisableAntiSpyware" 51 ) 52 # is_antivirus_disabled is either 0 (False) or 1 (True) 53 return bool(is_antivirus_disabled) 54 except FileNotFoundError: 55 return True 56 57 58def get_windefender_exclusion_paths(): 59 import winreg 60 61 paths = [] 62 try: 63 with winreg.OpenKeyEx( 64 winreg.HKEY_LOCAL_MACHINE, 65 r"SOFTWARE\Microsoft\Windows Defender\Exclusions\Paths", 66 ) as exclusions_key: 67 _, values_count, __ = winreg.QueryInfoKey(exclusions_key) 68 for i in range(0, values_count): 69 path, _, __ = winreg.EnumValue(exclusions_key, i) 70 paths.append(path) 71 except FileNotFoundError: 72 pass 73 74 return paths 75 76 77def is_windefender_affecting_srcdir(srcdir): 78 if get_is_windefender_disabled(): 79 return False 80 81 # When there's a match, but path cases aren't the same between srcdir and exclusion_path, 82 # commonpath will use the casing of the first path provided. 83 # To avoid surprises here, we normcase(...) so we don't get unexpected breakage if we change 84 # the path order. 85 srcdir = os.path.normcase(os.path.abspath(srcdir)) 86 87 try: 88 exclusion_paths = get_windefender_exclusion_paths() 89 except OSError as e: 90 if e.winerror == 5: 91 # A version of Windows 10 released in 2021 raises an "Access is denied" 92 # error (ERROR_ACCESS_DENIED == 5) to un-elevated processes when they 93 # query Windows Defender's exclusions. Skip the exclusion path checking. 94 return 95 raise 96 97 for exclusion_path in exclusion_paths: 98 exclusion_path = os.path.normcase(os.path.abspath(exclusion_path)) 99 try: 100 if os.path.commonpath([exclusion_path, srcdir]) == exclusion_path: 101 # exclusion_path is an ancestor of srcdir 102 return False 103 except ValueError: 104 # ValueError: Paths don't have the same drive - can't be ours 105 pass 106 return True 107 108 109class MozillaBuildBootstrapper(BaseBootstrapper): 110 """Bootstrapper for MozillaBuild to install rustup.""" 111 112 INSTALL_PYTHON_GUIDANCE = ( 113 "Python is provided by MozillaBuild; ensure your MozillaBuild " 114 "installation is up to date." 115 ) 116 117 def __init__(self, no_interactive=False, no_system_changes=False): 118 BaseBootstrapper.__init__( 119 self, no_interactive=no_interactive, no_system_changes=no_system_changes 120 ) 121 122 def validate_environment(self, srcdir): 123 if self.application.startswith("mobile_android"): 124 print( 125 "WARNING!!! Building Firefox for Android on Windows is not " 126 "fully supported. See https://bugzilla.mozilla.org/show_bug." 127 "cgi?id=1169873 for details.", 128 file=sys.stderr, 129 ) 130 131 if is_windefender_affecting_srcdir(srcdir): 132 print( 133 "Warning: the Firefox checkout directory is currently not in the " 134 "Windows Defender exclusion list. This can cause the build process " 135 "to be dramatically slowed or broken. To resolve this, follow the " 136 "directions here: " 137 "https://firefox-source-docs.mozilla.org/setup/windows_build.html" 138 "#antivirus-performance", 139 file=sys.stderr, 140 ) 141 142 def install_system_packages(self): 143 pass 144 145 def upgrade_mercurial(self, current): 146 # Mercurial upstream sometimes doesn't upload wheels, and building 147 # from source requires MS Visual C++ 9.0. So we force pip to install 148 # the last version that comes with wheels. 149 self.pip_install("mercurial", "--only-binary", "mercurial") 150 151 def install_browser_packages(self, mozconfig_builder): 152 pass 153 154 def install_browser_artifact_mode_packages(self, mozconfig_builder): 155 pass 156 157 def install_mobile_android_packages(self, mozconfig_builder): 158 self.ensure_mobile_android_packages(mozconfig_builder) 159 160 def install_mobile_android_artifact_mode_packages(self, mozconfig_builder): 161 self.ensure_mobile_android_packages(mozconfig_builder, artifact_mode=True) 162 163 def ensure_mobile_android_packages(self, mozconfig_builder, artifact_mode=False): 164 java_bin_dir = self.ensure_java(mozconfig_builder) 165 from mach.util import setenv 166 167 setenv("PATH", "{}{}{}".format(java_bin_dir, os.pathsep, os.environ["PATH"])) 168 169 from mozboot import android 170 171 android.ensure_android( 172 "windows", artifact_mode=artifact_mode, no_interactive=self.no_interactive 173 ) 174 175 def generate_mobile_android_mozconfig(self, artifact_mode=False): 176 from mozboot import android 177 178 return android.generate_mozconfig("windows", artifact_mode=artifact_mode) 179 180 def generate_mobile_android_artifact_mode_mozconfig(self): 181 return self.generate_mobile_android_mozconfig(artifact_mode=True) 182 183 def ensure_clang_static_analysis_package(self, state_dir, checkout_root): 184 from mozboot import static_analysis 185 186 self.install_toolchain_static_analysis( 187 state_dir, checkout_root, static_analysis.WINDOWS_CLANG_TIDY 188 ) 189 190 def ensure_sccache_packages(self, state_dir, checkout_root): 191 from mozboot import sccache 192 193 self.install_toolchain_artifact(state_dir, checkout_root, sccache.WIN64_SCCACHE) 194 self.install_toolchain_artifact( 195 state_dir, checkout_root, sccache.RUSTC_DIST_TOOLCHAIN, no_unpack=True 196 ) 197 self.install_toolchain_artifact( 198 state_dir, checkout_root, sccache.CLANG_DIST_TOOLCHAIN, no_unpack=True 199 ) 200 201 def ensure_stylo_packages(self, state_dir, checkout_root): 202 # On-device artifact builds are supported; on-device desktop builds are not. 203 if is_aarch64_host(): 204 raise Exception( 205 "You should not be performing desktop builds on an " 206 "AArch64 device. If you want to do artifact builds " 207 "instead, please choose the appropriate artifact build " 208 "option when beginning bootstrap." 209 ) 210 211 from mozboot import stylo 212 213 self.install_toolchain_artifact(state_dir, checkout_root, stylo.WINDOWS_CLANG) 214 self.install_toolchain_artifact( 215 state_dir, checkout_root, stylo.WINDOWS_CBINDGEN 216 ) 217 218 def ensure_nasm_packages(self, state_dir, checkout_root): 219 from mozboot import nasm 220 221 self.install_toolchain_artifact(state_dir, checkout_root, nasm.WINDOWS_NASM) 222 223 def ensure_node_packages(self, state_dir, checkout_root): 224 from mozboot import node 225 226 # We don't have native aarch64 node available, but aarch64 windows 227 # runs x86 binaries, so just use the x86 packages for such hosts. 228 node_artifact = node.WIN32 if is_aarch64_host() else node.WIN64 229 self.install_toolchain_artifact(state_dir, checkout_root, node_artifact) 230 231 def ensure_dump_syms_packages(self, state_dir, checkout_root): 232 from mozboot import dump_syms 233 234 self.install_toolchain_artifact( 235 state_dir, checkout_root, dump_syms.WIN64_DUMP_SYMS 236 ) 237 238 def ensure_fix_stacks_packages(self, state_dir, checkout_root): 239 from mozboot import fix_stacks 240 241 self.install_toolchain_artifact( 242 state_dir, checkout_root, fix_stacks.WINDOWS_FIX_STACKS 243 ) 244 245 def ensure_minidump_stackwalk_packages(self, state_dir, checkout_root): 246 from mozboot import minidump_stackwalk 247 248 self.install_toolchain_artifact( 249 state_dir, checkout_root, minidump_stackwalk.WINDOWS_MINIDUMP_STACKWALK 250 ) 251 252 def _update_package_manager(self): 253 pass 254 255 def run(self, command): 256 subprocess.check_call(command, stdin=sys.stdin) 257 258 def pip_install(self, *packages): 259 pip_dir = os.path.join( 260 os.environ["MOZILLABUILD"], "python", "Scripts", "pip.exe" 261 ) 262 command = [pip_dir, "install", "--upgrade"] 263 command.extend(packages) 264 self.run(command) 265