1*635a8641SAndroid Build Coastguard Worker#!/usr/bin/env python 2*635a8641SAndroid Build Coastguard Worker# Copyright 2014 The Chromium Authors. All rights reserved. 3*635a8641SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*635a8641SAndroid Build Coastguard Worker# found in the LICENSE file. 5*635a8641SAndroid Build Coastguard Worker 6*635a8641SAndroid Build Coastguard Workerimport glob 7*635a8641SAndroid Build Coastguard Workerimport json 8*635a8641SAndroid Build Coastguard Workerimport os 9*635a8641SAndroid Build Coastguard Workerimport pipes 10*635a8641SAndroid Build Coastguard Workerimport platform 11*635a8641SAndroid Build Coastguard Workerimport re 12*635a8641SAndroid Build Coastguard Workerimport shutil 13*635a8641SAndroid Build Coastguard Workerimport stat 14*635a8641SAndroid Build Coastguard Workerimport subprocess 15*635a8641SAndroid Build Coastguard Workerimport sys 16*635a8641SAndroid Build Coastguard Workerfrom gn_helpers import ToGNString 17*635a8641SAndroid Build Coastguard Worker 18*635a8641SAndroid Build Coastguard Worker 19*635a8641SAndroid Build Coastguard Workerscript_dir = os.path.dirname(os.path.realpath(__file__)) 20*635a8641SAndroid Build Coastguard Workerchrome_src = os.path.abspath(os.path.join(script_dir, os.pardir)) 21*635a8641SAndroid Build Coastguard WorkerSRC_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 22*635a8641SAndroid Build Coastguard Workersys.path.insert(0, os.path.join(chrome_src, 'tools', 'gyp', 'pylib')) 23*635a8641SAndroid Build Coastguard Workerjson_data_file = os.path.join(script_dir, 'win_toolchain.json') 24*635a8641SAndroid Build Coastguard Worker 25*635a8641SAndroid Build Coastguard Worker 26*635a8641SAndroid Build Coastguard Worker# Use MSVS2017 as the default toolchain. 27*635a8641SAndroid Build Coastguard WorkerCURRENT_DEFAULT_TOOLCHAIN_VERSION = '2017' 28*635a8641SAndroid Build Coastguard Worker 29*635a8641SAndroid Build Coastguard Worker 30*635a8641SAndroid Build Coastguard Workerdef SetEnvironmentAndGetRuntimeDllDirs(): 31*635a8641SAndroid Build Coastguard Worker """Sets up os.environ to use the depot_tools VS toolchain with gyp, and 32*635a8641SAndroid Build Coastguard Worker returns the location of the VS runtime DLLs so they can be copied into 33*635a8641SAndroid Build Coastguard Worker the output directory after gyp generation. 34*635a8641SAndroid Build Coastguard Worker 35*635a8641SAndroid Build Coastguard Worker Return value is [x64path, x86path] or None 36*635a8641SAndroid Build Coastguard Worker """ 37*635a8641SAndroid Build Coastguard Worker vs_runtime_dll_dirs = None 38*635a8641SAndroid Build Coastguard Worker depot_tools_win_toolchain = \ 39*635a8641SAndroid Build Coastguard Worker bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1'))) 40*635a8641SAndroid Build Coastguard Worker # When running on a non-Windows host, only do this if the SDK has explicitly 41*635a8641SAndroid Build Coastguard Worker # been downloaded before (in which case json_data_file will exist). 42*635a8641SAndroid Build Coastguard Worker if ((sys.platform in ('win32', 'cygwin') or os.path.exists(json_data_file)) 43*635a8641SAndroid Build Coastguard Worker and depot_tools_win_toolchain): 44*635a8641SAndroid Build Coastguard Worker if ShouldUpdateToolchain(): 45*635a8641SAndroid Build Coastguard Worker update_result = Update() 46*635a8641SAndroid Build Coastguard Worker if update_result != 0: 47*635a8641SAndroid Build Coastguard Worker raise Exception('Failed to update, error code %d.' % update_result) 48*635a8641SAndroid Build Coastguard Worker with open(json_data_file, 'r') as tempf: 49*635a8641SAndroid Build Coastguard Worker toolchain_data = json.load(tempf) 50*635a8641SAndroid Build Coastguard Worker 51*635a8641SAndroid Build Coastguard Worker toolchain = toolchain_data['path'] 52*635a8641SAndroid Build Coastguard Worker version = toolchain_data['version'] 53*635a8641SAndroid Build Coastguard Worker win_sdk = toolchain_data.get('win_sdk') 54*635a8641SAndroid Build Coastguard Worker if not win_sdk: 55*635a8641SAndroid Build Coastguard Worker win_sdk = toolchain_data['win8sdk'] 56*635a8641SAndroid Build Coastguard Worker wdk = toolchain_data['wdk'] 57*635a8641SAndroid Build Coastguard Worker # TODO(scottmg): The order unfortunately matters in these. They should be 58*635a8641SAndroid Build Coastguard Worker # split into separate keys for x86 and x64. (See CopyDlls call below). 59*635a8641SAndroid Build Coastguard Worker # http://crbug.com/345992 60*635a8641SAndroid Build Coastguard Worker vs_runtime_dll_dirs = toolchain_data['runtime_dirs'] 61*635a8641SAndroid Build Coastguard Worker 62*635a8641SAndroid Build Coastguard Worker os.environ['GYP_MSVS_OVERRIDE_PATH'] = toolchain 63*635a8641SAndroid Build Coastguard Worker os.environ['GYP_MSVS_VERSION'] = version 64*635a8641SAndroid Build Coastguard Worker 65*635a8641SAndroid Build Coastguard Worker os.environ['WINDOWSSDKDIR'] = win_sdk 66*635a8641SAndroid Build Coastguard Worker os.environ['WDK_DIR'] = wdk 67*635a8641SAndroid Build Coastguard Worker # Include the VS runtime in the PATH in case it's not machine-installed. 68*635a8641SAndroid Build Coastguard Worker runtime_path = os.path.pathsep.join(vs_runtime_dll_dirs) 69*635a8641SAndroid Build Coastguard Worker os.environ['PATH'] = runtime_path + os.path.pathsep + os.environ['PATH'] 70*635a8641SAndroid Build Coastguard Worker elif sys.platform == 'win32' and not depot_tools_win_toolchain: 71*635a8641SAndroid Build Coastguard Worker if not 'GYP_MSVS_OVERRIDE_PATH' in os.environ: 72*635a8641SAndroid Build Coastguard Worker os.environ['GYP_MSVS_OVERRIDE_PATH'] = DetectVisualStudioPath() 73*635a8641SAndroid Build Coastguard Worker if not 'GYP_MSVS_VERSION' in os.environ: 74*635a8641SAndroid Build Coastguard Worker os.environ['GYP_MSVS_VERSION'] = GetVisualStudioVersion() 75*635a8641SAndroid Build Coastguard Worker 76*635a8641SAndroid Build Coastguard Worker # When using an installed toolchain these files aren't needed in the output 77*635a8641SAndroid Build Coastguard Worker # directory in order to run binaries locally, but they are needed in order 78*635a8641SAndroid Build Coastguard Worker # to create isolates or the mini_installer. Copying them to the output 79*635a8641SAndroid Build Coastguard Worker # directory ensures that they are available when needed. 80*635a8641SAndroid Build Coastguard Worker bitness = platform.architecture()[0] 81*635a8641SAndroid Build Coastguard Worker # When running 64-bit python the x64 DLLs will be in System32 82*635a8641SAndroid Build Coastguard Worker x64_path = 'System32' if bitness == '64bit' else 'Sysnative' 83*635a8641SAndroid Build Coastguard Worker x64_path = os.path.join(os.path.expandvars('%windir%'), x64_path) 84*635a8641SAndroid Build Coastguard Worker vs_runtime_dll_dirs = [x64_path, os.path.expandvars('%windir%/SysWOW64')] 85*635a8641SAndroid Build Coastguard Worker 86*635a8641SAndroid Build Coastguard Worker return vs_runtime_dll_dirs 87*635a8641SAndroid Build Coastguard Worker 88*635a8641SAndroid Build Coastguard Worker 89*635a8641SAndroid Build Coastguard Workerdef _RegistryGetValueUsingWinReg(key, value): 90*635a8641SAndroid Build Coastguard Worker """Use the _winreg module to obtain the value of a registry key. 91*635a8641SAndroid Build Coastguard Worker 92*635a8641SAndroid Build Coastguard Worker Args: 93*635a8641SAndroid Build Coastguard Worker key: The registry key. 94*635a8641SAndroid Build Coastguard Worker value: The particular registry value to read. 95*635a8641SAndroid Build Coastguard Worker Return: 96*635a8641SAndroid Build Coastguard Worker contents of the registry key's value, or None on failure. Throws 97*635a8641SAndroid Build Coastguard Worker ImportError if _winreg is unavailable. 98*635a8641SAndroid Build Coastguard Worker """ 99*635a8641SAndroid Build Coastguard Worker import _winreg 100*635a8641SAndroid Build Coastguard Worker try: 101*635a8641SAndroid Build Coastguard Worker root, subkey = key.split('\\', 1) 102*635a8641SAndroid Build Coastguard Worker assert root == 'HKLM' # Only need HKLM for now. 103*635a8641SAndroid Build Coastguard Worker with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, subkey) as hkey: 104*635a8641SAndroid Build Coastguard Worker return _winreg.QueryValueEx(hkey, value)[0] 105*635a8641SAndroid Build Coastguard Worker except WindowsError: 106*635a8641SAndroid Build Coastguard Worker return None 107*635a8641SAndroid Build Coastguard Worker 108*635a8641SAndroid Build Coastguard Worker 109*635a8641SAndroid Build Coastguard Workerdef _RegistryGetValue(key, value): 110*635a8641SAndroid Build Coastguard Worker try: 111*635a8641SAndroid Build Coastguard Worker return _RegistryGetValueUsingWinReg(key, value) 112*635a8641SAndroid Build Coastguard Worker except ImportError: 113*635a8641SAndroid Build Coastguard Worker raise Exception('The python library _winreg not found.') 114*635a8641SAndroid Build Coastguard Worker 115*635a8641SAndroid Build Coastguard Worker 116*635a8641SAndroid Build Coastguard Workerdef GetVisualStudioVersion(): 117*635a8641SAndroid Build Coastguard Worker """Return GYP_MSVS_VERSION of Visual Studio. 118*635a8641SAndroid Build Coastguard Worker """ 119*635a8641SAndroid Build Coastguard Worker return os.environ.get('GYP_MSVS_VERSION', CURRENT_DEFAULT_TOOLCHAIN_VERSION) 120*635a8641SAndroid Build Coastguard Worker 121*635a8641SAndroid Build Coastguard Worker 122*635a8641SAndroid Build Coastguard Workerdef DetectVisualStudioPath(): 123*635a8641SAndroid Build Coastguard Worker """Return path to the GYP_MSVS_VERSION of Visual Studio. 124*635a8641SAndroid Build Coastguard Worker """ 125*635a8641SAndroid Build Coastguard Worker 126*635a8641SAndroid Build Coastguard Worker # Note that this code is used from 127*635a8641SAndroid Build Coastguard Worker # build/toolchain/win/setup_toolchain.py as well. 128*635a8641SAndroid Build Coastguard Worker version_as_year = GetVisualStudioVersion() 129*635a8641SAndroid Build Coastguard Worker year_to_version = { 130*635a8641SAndroid Build Coastguard Worker '2017': '15.0', 131*635a8641SAndroid Build Coastguard Worker } 132*635a8641SAndroid Build Coastguard Worker if version_as_year not in year_to_version: 133*635a8641SAndroid Build Coastguard Worker raise Exception(('Visual Studio version %s (from GYP_MSVS_VERSION)' 134*635a8641SAndroid Build Coastguard Worker ' not supported. Supported versions are: %s') % ( 135*635a8641SAndroid Build Coastguard Worker version_as_year, ', '.join(year_to_version.keys()))) 136*635a8641SAndroid Build Coastguard Worker version = year_to_version[version_as_year] 137*635a8641SAndroid Build Coastguard Worker if version_as_year == '2017': 138*635a8641SAndroid Build Coastguard Worker # The VC++ 2017 install location needs to be located using COM instead of 139*635a8641SAndroid Build Coastguard Worker # the registry. For details see: 140*635a8641SAndroid Build Coastguard Worker # https://blogs.msdn.microsoft.com/heaths/2016/09/15/changes-to-visual-studio-15-setup/ 141*635a8641SAndroid Build Coastguard Worker # For now we use a hardcoded default with an environment variable override. 142*635a8641SAndroid Build Coastguard Worker for path in ( 143*635a8641SAndroid Build Coastguard Worker os.environ.get('vs2017_install'), 144*635a8641SAndroid Build Coastguard Worker os.path.expandvars('%ProgramFiles(x86)%' 145*635a8641SAndroid Build Coastguard Worker '/Microsoft Visual Studio/2017/Enterprise'), 146*635a8641SAndroid Build Coastguard Worker os.path.expandvars('%ProgramFiles(x86)%' 147*635a8641SAndroid Build Coastguard Worker '/Microsoft Visual Studio/2017/Professional'), 148*635a8641SAndroid Build Coastguard Worker os.path.expandvars('%ProgramFiles(x86)%' 149*635a8641SAndroid Build Coastguard Worker '/Microsoft Visual Studio/2017/Community')): 150*635a8641SAndroid Build Coastguard Worker if path and os.path.exists(path): 151*635a8641SAndroid Build Coastguard Worker return path 152*635a8641SAndroid Build Coastguard Worker 153*635a8641SAndroid Build Coastguard Worker raise Exception(('Visual Studio Version %s (from GYP_MSVS_VERSION)' 154*635a8641SAndroid Build Coastguard Worker ' not found.') % (version_as_year)) 155*635a8641SAndroid Build Coastguard Worker 156*635a8641SAndroid Build Coastguard Worker 157*635a8641SAndroid Build Coastguard Workerdef _CopyRuntimeImpl(target, source, verbose=True): 158*635a8641SAndroid Build Coastguard Worker """Copy |source| to |target| if it doesn't already exist or if it needs to be 159*635a8641SAndroid Build Coastguard Worker updated (comparing last modified time as an approximate float match as for 160*635a8641SAndroid Build Coastguard Worker some reason the values tend to differ by ~1e-07 despite being copies of the 161*635a8641SAndroid Build Coastguard Worker same file... https://crbug.com/603603). 162*635a8641SAndroid Build Coastguard Worker """ 163*635a8641SAndroid Build Coastguard Worker if (os.path.isdir(os.path.dirname(target)) and 164*635a8641SAndroid Build Coastguard Worker (not os.path.isfile(target) or 165*635a8641SAndroid Build Coastguard Worker abs(os.stat(target).st_mtime - os.stat(source).st_mtime) >= 0.01)): 166*635a8641SAndroid Build Coastguard Worker if verbose: 167*635a8641SAndroid Build Coastguard Worker print('Copying %s to %s...' % (source, target)) 168*635a8641SAndroid Build Coastguard Worker if os.path.exists(target): 169*635a8641SAndroid Build Coastguard Worker # Make the file writable so that we can delete it now, and keep it 170*635a8641SAndroid Build Coastguard Worker # readable. 171*635a8641SAndroid Build Coastguard Worker os.chmod(target, stat.S_IWRITE | stat.S_IREAD) 172*635a8641SAndroid Build Coastguard Worker os.unlink(target) 173*635a8641SAndroid Build Coastguard Worker shutil.copy2(source, target) 174*635a8641SAndroid Build Coastguard Worker # Make the file writable so that we can overwrite or delete it later, 175*635a8641SAndroid Build Coastguard Worker # keep it readable. 176*635a8641SAndroid Build Coastguard Worker os.chmod(target, stat.S_IWRITE | stat.S_IREAD) 177*635a8641SAndroid Build Coastguard Worker 178*635a8641SAndroid Build Coastguard Worker 179*635a8641SAndroid Build Coastguard Workerdef _CopyUCRTRuntime(target_dir, source_dir, target_cpu, dll_pattern, suffix): 180*635a8641SAndroid Build Coastguard Worker """Copy both the msvcp and vccorlib runtime DLLs, only if the target doesn't 181*635a8641SAndroid Build Coastguard Worker exist, but the target directory does exist.""" 182*635a8641SAndroid Build Coastguard Worker for file_part in ('msvcp', 'vccorlib', 'vcruntime'): 183*635a8641SAndroid Build Coastguard Worker dll = dll_pattern % file_part 184*635a8641SAndroid Build Coastguard Worker target = os.path.join(target_dir, dll) 185*635a8641SAndroid Build Coastguard Worker source = os.path.join(source_dir, dll) 186*635a8641SAndroid Build Coastguard Worker _CopyRuntimeImpl(target, source) 187*635a8641SAndroid Build Coastguard Worker # Copy the UCRT files from the Windows SDK. This location includes the 188*635a8641SAndroid Build Coastguard Worker # api-ms-win-crt-*.dll files that are not found in the Windows directory. 189*635a8641SAndroid Build Coastguard Worker # These files are needed for component builds. If WINDOWSSDKDIR is not set 190*635a8641SAndroid Build Coastguard Worker # use the default SDK path. This will be the case when 191*635a8641SAndroid Build Coastguard Worker # DEPOT_TOOLS_WIN_TOOLCHAIN=0 and vcvarsall.bat has not been run. 192*635a8641SAndroid Build Coastguard Worker win_sdk_dir = os.path.normpath( 193*635a8641SAndroid Build Coastguard Worker os.environ.get('WINDOWSSDKDIR', 194*635a8641SAndroid Build Coastguard Worker os.path.expandvars('%ProgramFiles(x86)%' 195*635a8641SAndroid Build Coastguard Worker '\\Windows Kits\\10'))) 196*635a8641SAndroid Build Coastguard Worker ucrt_dll_dirs = os.path.join(win_sdk_dir, 'Redist', 'ucrt', 'DLLs', 197*635a8641SAndroid Build Coastguard Worker target_cpu) 198*635a8641SAndroid Build Coastguard Worker ucrt_files = glob.glob(os.path.join(ucrt_dll_dirs, 'api-ms-win-*.dll')) 199*635a8641SAndroid Build Coastguard Worker assert len(ucrt_files) > 0 200*635a8641SAndroid Build Coastguard Worker for ucrt_src_file in ucrt_files: 201*635a8641SAndroid Build Coastguard Worker file_part = os.path.basename(ucrt_src_file) 202*635a8641SAndroid Build Coastguard Worker ucrt_dst_file = os.path.join(target_dir, file_part) 203*635a8641SAndroid Build Coastguard Worker _CopyRuntimeImpl(ucrt_dst_file, ucrt_src_file, False) 204*635a8641SAndroid Build Coastguard Worker _CopyRuntimeImpl(os.path.join(target_dir, 'ucrtbase' + suffix), 205*635a8641SAndroid Build Coastguard Worker os.path.join(source_dir, 'ucrtbase' + suffix)) 206*635a8641SAndroid Build Coastguard Worker 207*635a8641SAndroid Build Coastguard Worker 208*635a8641SAndroid Build Coastguard Workerdef FindVCToolsRoot(): 209*635a8641SAndroid Build Coastguard Worker """In VS2017 the PGO runtime dependencies are located in 210*635a8641SAndroid Build Coastguard Worker {toolchain_root}/VC/Tools/MSVC/{x.y.z}/bin/Host{target_cpu}/{target_cpu}/, the 211*635a8641SAndroid Build Coastguard Worker {version_number} part is likely to change in case of a minor update of the 212*635a8641SAndroid Build Coastguard Worker toolchain so we don't hardcode this value here (except for the major number). 213*635a8641SAndroid Build Coastguard Worker 214*635a8641SAndroid Build Coastguard Worker This returns the '{toolchain_root}/VC/Tools/MSVC/{x.y.z}/bin/' path. 215*635a8641SAndroid Build Coastguard Worker 216*635a8641SAndroid Build Coastguard Worker This function should only be called when using VS2017. 217*635a8641SAndroid Build Coastguard Worker """ 218*635a8641SAndroid Build Coastguard Worker assert GetVisualStudioVersion() == '2017' 219*635a8641SAndroid Build Coastguard Worker SetEnvironmentAndGetRuntimeDllDirs() 220*635a8641SAndroid Build Coastguard Worker assert ('GYP_MSVS_OVERRIDE_PATH' in os.environ) 221*635a8641SAndroid Build Coastguard Worker vc_tools_msvc_root = os.path.join(os.environ['GYP_MSVS_OVERRIDE_PATH'], 222*635a8641SAndroid Build Coastguard Worker 'VC', 'Tools', 'MSVC') 223*635a8641SAndroid Build Coastguard Worker for directory in os.listdir(vc_tools_msvc_root): 224*635a8641SAndroid Build Coastguard Worker if not os.path.isdir(os.path.join(vc_tools_msvc_root, directory)): 225*635a8641SAndroid Build Coastguard Worker continue 226*635a8641SAndroid Build Coastguard Worker if re.match('14\.\d+\.\d+', directory): 227*635a8641SAndroid Build Coastguard Worker return os.path.join(vc_tools_msvc_root, directory, 'bin') 228*635a8641SAndroid Build Coastguard Worker raise Exception('Unable to find the VC tools directory.') 229*635a8641SAndroid Build Coastguard Worker 230*635a8641SAndroid Build Coastguard Worker 231*635a8641SAndroid Build Coastguard Workerdef _CopyPGORuntime(target_dir, target_cpu): 232*635a8641SAndroid Build Coastguard Worker """Copy the runtime dependencies required during a PGO build. 233*635a8641SAndroid Build Coastguard Worker """ 234*635a8641SAndroid Build Coastguard Worker env_version = GetVisualStudioVersion() 235*635a8641SAndroid Build Coastguard Worker # These dependencies will be in a different location depending on the version 236*635a8641SAndroid Build Coastguard Worker # of the toolchain. 237*635a8641SAndroid Build Coastguard Worker if env_version == '2017': 238*635a8641SAndroid Build Coastguard Worker pgo_runtime_root = FindVCToolsRoot() 239*635a8641SAndroid Build Coastguard Worker assert pgo_runtime_root 240*635a8641SAndroid Build Coastguard Worker # There's no version of pgosweep.exe in HostX64/x86, so we use the copy 241*635a8641SAndroid Build Coastguard Worker # from HostX86/x86. 242*635a8641SAndroid Build Coastguard Worker pgo_x86_runtime_dir = os.path.join(pgo_runtime_root, 'HostX86', 'x86') 243*635a8641SAndroid Build Coastguard Worker pgo_x64_runtime_dir = os.path.join(pgo_runtime_root, 'HostX64', 'x64') 244*635a8641SAndroid Build Coastguard Worker else: 245*635a8641SAndroid Build Coastguard Worker raise Exception('Unexpected toolchain version: %s.' % env_version) 246*635a8641SAndroid Build Coastguard Worker 247*635a8641SAndroid Build Coastguard Worker # We need to copy 2 runtime dependencies used during the profiling step: 248*635a8641SAndroid Build Coastguard Worker # - pgort140.dll: runtime library required to run the instrumented image. 249*635a8641SAndroid Build Coastguard Worker # - pgosweep.exe: executable used to collect the profiling data 250*635a8641SAndroid Build Coastguard Worker pgo_runtimes = ['pgort140.dll', 'pgosweep.exe'] 251*635a8641SAndroid Build Coastguard Worker for runtime in pgo_runtimes: 252*635a8641SAndroid Build Coastguard Worker if target_cpu == 'x86': 253*635a8641SAndroid Build Coastguard Worker source = os.path.join(pgo_x86_runtime_dir, runtime) 254*635a8641SAndroid Build Coastguard Worker elif target_cpu == 'x64': 255*635a8641SAndroid Build Coastguard Worker source = os.path.join(pgo_x64_runtime_dir, runtime) 256*635a8641SAndroid Build Coastguard Worker else: 257*635a8641SAndroid Build Coastguard Worker raise NotImplementedError("Unexpected target_cpu value: " + target_cpu) 258*635a8641SAndroid Build Coastguard Worker if not os.path.exists(source): 259*635a8641SAndroid Build Coastguard Worker raise Exception('Unable to find %s.' % source) 260*635a8641SAndroid Build Coastguard Worker _CopyRuntimeImpl(os.path.join(target_dir, runtime), source) 261*635a8641SAndroid Build Coastguard Worker 262*635a8641SAndroid Build Coastguard Worker 263*635a8641SAndroid Build Coastguard Workerdef _CopyRuntime(target_dir, source_dir, target_cpu, debug): 264*635a8641SAndroid Build Coastguard Worker """Copy the VS runtime DLLs, only if the target doesn't exist, but the target 265*635a8641SAndroid Build Coastguard Worker directory does exist. Handles VS 2015 and VS 2017.""" 266*635a8641SAndroid Build Coastguard Worker suffix = "d.dll" if debug else ".dll" 267*635a8641SAndroid Build Coastguard Worker # VS 2017 uses the same CRT DLLs as VS 2015. 268*635a8641SAndroid Build Coastguard Worker _CopyUCRTRuntime(target_dir, source_dir, target_cpu, '%s140' + suffix, 269*635a8641SAndroid Build Coastguard Worker suffix) 270*635a8641SAndroid Build Coastguard Worker 271*635a8641SAndroid Build Coastguard Worker 272*635a8641SAndroid Build Coastguard Workerdef CopyDlls(target_dir, configuration, target_cpu): 273*635a8641SAndroid Build Coastguard Worker """Copy the VS runtime DLLs into the requested directory as needed. 274*635a8641SAndroid Build Coastguard Worker 275*635a8641SAndroid Build Coastguard Worker configuration is one of 'Debug' or 'Release'. 276*635a8641SAndroid Build Coastguard Worker target_cpu is one of 'x86' or 'x64'. 277*635a8641SAndroid Build Coastguard Worker 278*635a8641SAndroid Build Coastguard Worker The debug configuration gets both the debug and release DLLs; the 279*635a8641SAndroid Build Coastguard Worker release config only the latter. 280*635a8641SAndroid Build Coastguard Worker """ 281*635a8641SAndroid Build Coastguard Worker vs_runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs() 282*635a8641SAndroid Build Coastguard Worker if not vs_runtime_dll_dirs: 283*635a8641SAndroid Build Coastguard Worker return 284*635a8641SAndroid Build Coastguard Worker 285*635a8641SAndroid Build Coastguard Worker x64_runtime, x86_runtime = vs_runtime_dll_dirs 286*635a8641SAndroid Build Coastguard Worker runtime_dir = x64_runtime if target_cpu == 'x64' else x86_runtime 287*635a8641SAndroid Build Coastguard Worker _CopyRuntime(target_dir, runtime_dir, target_cpu, debug=False) 288*635a8641SAndroid Build Coastguard Worker if configuration == 'Debug': 289*635a8641SAndroid Build Coastguard Worker _CopyRuntime(target_dir, runtime_dir, target_cpu, debug=True) 290*635a8641SAndroid Build Coastguard Worker else: 291*635a8641SAndroid Build Coastguard Worker _CopyPGORuntime(target_dir, target_cpu) 292*635a8641SAndroid Build Coastguard Worker 293*635a8641SAndroid Build Coastguard Worker _CopyDebugger(target_dir, target_cpu) 294*635a8641SAndroid Build Coastguard Worker 295*635a8641SAndroid Build Coastguard Worker 296*635a8641SAndroid Build Coastguard Workerdef _CopyDebugger(target_dir, target_cpu): 297*635a8641SAndroid Build Coastguard Worker """Copy dbghelp.dll and dbgcore.dll into the requested directory as needed. 298*635a8641SAndroid Build Coastguard Worker 299*635a8641SAndroid Build Coastguard Worker target_cpu is one of 'x86' or 'x64'. 300*635a8641SAndroid Build Coastguard Worker 301*635a8641SAndroid Build Coastguard Worker dbghelp.dll is used when Chrome needs to symbolize stacks. Copying this file 302*635a8641SAndroid Build Coastguard Worker from the SDK directory avoids using the system copy of dbghelp.dll which then 303*635a8641SAndroid Build Coastguard Worker ensures compatibility with recent debug information formats, such as VS 304*635a8641SAndroid Build Coastguard Worker 2017 /debug:fastlink PDBs. 305*635a8641SAndroid Build Coastguard Worker 306*635a8641SAndroid Build Coastguard Worker dbgcore.dll is needed when using some functions from dbghelp.dll (like 307*635a8641SAndroid Build Coastguard Worker MinidumpWriteDump). 308*635a8641SAndroid Build Coastguard Worker """ 309*635a8641SAndroid Build Coastguard Worker win_sdk_dir = SetEnvironmentAndGetSDKDir() 310*635a8641SAndroid Build Coastguard Worker if not win_sdk_dir: 311*635a8641SAndroid Build Coastguard Worker return 312*635a8641SAndroid Build Coastguard Worker 313*635a8641SAndroid Build Coastguard Worker # List of debug files that should be copied, the first element of the tuple is 314*635a8641SAndroid Build Coastguard Worker # the name of the file and the second indicates if it's optional. 315*635a8641SAndroid Build Coastguard Worker debug_files = [('dbghelp.dll', False), ('dbgcore.dll', True)] 316*635a8641SAndroid Build Coastguard Worker for debug_file, is_optional in debug_files: 317*635a8641SAndroid Build Coastguard Worker full_path = os.path.join(win_sdk_dir, 'Debuggers', target_cpu, debug_file) 318*635a8641SAndroid Build Coastguard Worker if not os.path.exists(full_path): 319*635a8641SAndroid Build Coastguard Worker if is_optional: 320*635a8641SAndroid Build Coastguard Worker continue 321*635a8641SAndroid Build Coastguard Worker else: 322*635a8641SAndroid Build Coastguard Worker # TODO(crbug.com/773476): remove version requirement. 323*635a8641SAndroid Build Coastguard Worker raise Exception('%s not found in "%s"\r\nYou must install the ' 324*635a8641SAndroid Build Coastguard Worker '"Debugging Tools for Windows" feature from the Windows' 325*635a8641SAndroid Build Coastguard Worker ' 10 SDK. You must use v10.0.17134.0. of the SDK' 326*635a8641SAndroid Build Coastguard Worker % (debug_file, full_path)) 327*635a8641SAndroid Build Coastguard Worker target_path = os.path.join(target_dir, debug_file) 328*635a8641SAndroid Build Coastguard Worker _CopyRuntimeImpl(target_path, full_path) 329*635a8641SAndroid Build Coastguard Worker 330*635a8641SAndroid Build Coastguard Worker 331*635a8641SAndroid Build Coastguard Workerdef _GetDesiredVsToolchainHashes(): 332*635a8641SAndroid Build Coastguard Worker """Load a list of SHA1s corresponding to the toolchains that we want installed 333*635a8641SAndroid Build Coastguard Worker to build with.""" 334*635a8641SAndroid Build Coastguard Worker env_version = GetVisualStudioVersion() 335*635a8641SAndroid Build Coastguard Worker if env_version == '2017': 336*635a8641SAndroid Build Coastguard Worker # VS 2017 Update 7.1 (15.7.1) with 10.0.17134.12 SDK, rebuilt with 337*635a8641SAndroid Build Coastguard Worker # dbghelp.dll fix. 338*635a8641SAndroid Build Coastguard Worker toolchain_hash = '3bc0ec615cf20ee342f3bc29bc991b5ad66d8d2c' 339*635a8641SAndroid Build Coastguard Worker # Third parties that do not have access to the canonical toolchain can map 340*635a8641SAndroid Build Coastguard Worker # canonical toolchain version to their own toolchain versions. 341*635a8641SAndroid Build Coastguard Worker toolchain_hash_mapping_key = 'GYP_MSVS_HASH_%s' % toolchain_hash 342*635a8641SAndroid Build Coastguard Worker return [os.environ.get(toolchain_hash_mapping_key, toolchain_hash)] 343*635a8641SAndroid Build Coastguard Worker raise Exception('Unsupported VS version %s' % env_version) 344*635a8641SAndroid Build Coastguard Worker 345*635a8641SAndroid Build Coastguard Worker 346*635a8641SAndroid Build Coastguard Workerdef ShouldUpdateToolchain(): 347*635a8641SAndroid Build Coastguard Worker """Check if the toolchain should be upgraded.""" 348*635a8641SAndroid Build Coastguard Worker if not os.path.exists(json_data_file): 349*635a8641SAndroid Build Coastguard Worker return True 350*635a8641SAndroid Build Coastguard Worker with open(json_data_file, 'r') as tempf: 351*635a8641SAndroid Build Coastguard Worker toolchain_data = json.load(tempf) 352*635a8641SAndroid Build Coastguard Worker version = toolchain_data['version'] 353*635a8641SAndroid Build Coastguard Worker env_version = GetVisualStudioVersion() 354*635a8641SAndroid Build Coastguard Worker # If there's a mismatch between the version set in the environment and the one 355*635a8641SAndroid Build Coastguard Worker # in the json file then the toolchain should be updated. 356*635a8641SAndroid Build Coastguard Worker return version != env_version 357*635a8641SAndroid Build Coastguard Worker 358*635a8641SAndroid Build Coastguard Worker 359*635a8641SAndroid Build Coastguard Workerdef Update(force=False): 360*635a8641SAndroid Build Coastguard Worker """Requests an update of the toolchain to the specific hashes we have at 361*635a8641SAndroid Build Coastguard Worker this revision. The update outputs a .json of the various configuration 362*635a8641SAndroid Build Coastguard Worker information required to pass to gyp which we use in |GetToolchainDir()|. 363*635a8641SAndroid Build Coastguard Worker """ 364*635a8641SAndroid Build Coastguard Worker if force != False and force != '--force': 365*635a8641SAndroid Build Coastguard Worker print('Unknown parameter "%s"' % force, file=sys.stderr) 366*635a8641SAndroid Build Coastguard Worker return 1 367*635a8641SAndroid Build Coastguard Worker if force == '--force' or os.path.exists(json_data_file): 368*635a8641SAndroid Build Coastguard Worker force = True 369*635a8641SAndroid Build Coastguard Worker 370*635a8641SAndroid Build Coastguard Worker depot_tools_win_toolchain = \ 371*635a8641SAndroid Build Coastguard Worker bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1'))) 372*635a8641SAndroid Build Coastguard Worker if ((sys.platform in ('win32', 'cygwin') or force) and 373*635a8641SAndroid Build Coastguard Worker depot_tools_win_toolchain): 374*635a8641SAndroid Build Coastguard Worker import find_depot_tools 375*635a8641SAndroid Build Coastguard Worker depot_tools_path = find_depot_tools.add_depot_tools_to_path() 376*635a8641SAndroid Build Coastguard Worker 377*635a8641SAndroid Build Coastguard Worker # On Linux, the file system is usually case-sensitive while the Windows 378*635a8641SAndroid Build Coastguard Worker # SDK only works on case-insensitive file systems. If it doesn't already 379*635a8641SAndroid Build Coastguard Worker # exist, set up a ciopfs fuse mount to put the SDK in a case-insensitive 380*635a8641SAndroid Build Coastguard Worker # part of the file system. 381*635a8641SAndroid Build Coastguard Worker toolchain_dir = os.path.join(depot_tools_path, 'win_toolchain', 'vs_files') 382*635a8641SAndroid Build Coastguard Worker # For testing this block, unmount existing mounts with 383*635a8641SAndroid Build Coastguard Worker # fusermount -u third_party/depot_tools/win_toolchain/vs_files 384*635a8641SAndroid Build Coastguard Worker if sys.platform.startswith('linux') and not os.path.ismount(toolchain_dir): 385*635a8641SAndroid Build Coastguard Worker import distutils.spawn 386*635a8641SAndroid Build Coastguard Worker ciopfs = distutils.spawn.find_executable('ciopfs') 387*635a8641SAndroid Build Coastguard Worker if not ciopfs: 388*635a8641SAndroid Build Coastguard Worker # ciopfs not found in PATH; try the one downloaded from the DEPS hook. 389*635a8641SAndroid Build Coastguard Worker ciopfs = os.path.join(script_dir, 'ciopfs') 390*635a8641SAndroid Build Coastguard Worker if not os.path.isdir(toolchain_dir): 391*635a8641SAndroid Build Coastguard Worker os.mkdir(toolchain_dir) 392*635a8641SAndroid Build Coastguard Worker if not os.path.isdir(toolchain_dir + '.ciopfs'): 393*635a8641SAndroid Build Coastguard Worker os.mkdir(toolchain_dir + '.ciopfs') 394*635a8641SAndroid Build Coastguard Worker # Without use_ino, clang's #pragma once and Wnonportable-include-path 395*635a8641SAndroid Build Coastguard Worker # both don't work right, see https://llvm.org/PR34931 396*635a8641SAndroid Build Coastguard Worker # use_ino doesn't slow down builds, so it seems there's no drawback to 397*635a8641SAndroid Build Coastguard Worker # just using it always. 398*635a8641SAndroid Build Coastguard Worker subprocess.check_call([ 399*635a8641SAndroid Build Coastguard Worker ciopfs, '-o', 'use_ino', toolchain_dir + '.ciopfs', toolchain_dir]) 400*635a8641SAndroid Build Coastguard Worker 401*635a8641SAndroid Build Coastguard Worker # Necessary so that get_toolchain_if_necessary.py will put the VS toolkit 402*635a8641SAndroid Build Coastguard Worker # in the correct directory. 403*635a8641SAndroid Build Coastguard Worker os.environ['GYP_MSVS_VERSION'] = GetVisualStudioVersion() 404*635a8641SAndroid Build Coastguard Worker get_toolchain_args = [ 405*635a8641SAndroid Build Coastguard Worker sys.executable, 406*635a8641SAndroid Build Coastguard Worker os.path.join(depot_tools_path, 407*635a8641SAndroid Build Coastguard Worker 'win_toolchain', 408*635a8641SAndroid Build Coastguard Worker 'get_toolchain_if_necessary.py'), 409*635a8641SAndroid Build Coastguard Worker '--output-json', json_data_file, 410*635a8641SAndroid Build Coastguard Worker ] + _GetDesiredVsToolchainHashes() 411*635a8641SAndroid Build Coastguard Worker if force: 412*635a8641SAndroid Build Coastguard Worker get_toolchain_args.append('--force') 413*635a8641SAndroid Build Coastguard Worker subprocess.check_call(get_toolchain_args) 414*635a8641SAndroid Build Coastguard Worker 415*635a8641SAndroid Build Coastguard Worker return 0 416*635a8641SAndroid Build Coastguard Worker 417*635a8641SAndroid Build Coastguard Worker 418*635a8641SAndroid Build Coastguard Workerdef NormalizePath(path): 419*635a8641SAndroid Build Coastguard Worker while path.endswith("\\"): 420*635a8641SAndroid Build Coastguard Worker path = path[:-1] 421*635a8641SAndroid Build Coastguard Worker return path 422*635a8641SAndroid Build Coastguard Worker 423*635a8641SAndroid Build Coastguard Worker 424*635a8641SAndroid Build Coastguard Workerdef SetEnvironmentAndGetSDKDir(): 425*635a8641SAndroid Build Coastguard Worker """Gets location information about the current sdk (must have been 426*635a8641SAndroid Build Coastguard Worker previously updated by 'update'). This is used for the GN build.""" 427*635a8641SAndroid Build Coastguard Worker SetEnvironmentAndGetRuntimeDllDirs() 428*635a8641SAndroid Build Coastguard Worker 429*635a8641SAndroid Build Coastguard Worker # If WINDOWSSDKDIR is not set, search the default SDK path and set it. 430*635a8641SAndroid Build Coastguard Worker if not 'WINDOWSSDKDIR' in os.environ: 431*635a8641SAndroid Build Coastguard Worker default_sdk_path = os.path.expandvars('%ProgramFiles(x86)%' 432*635a8641SAndroid Build Coastguard Worker '\\Windows Kits\\10') 433*635a8641SAndroid Build Coastguard Worker if os.path.isdir(default_sdk_path): 434*635a8641SAndroid Build Coastguard Worker os.environ['WINDOWSSDKDIR'] = default_sdk_path 435*635a8641SAndroid Build Coastguard Worker 436*635a8641SAndroid Build Coastguard Worker return NormalizePath(os.environ['WINDOWSSDKDIR']) 437*635a8641SAndroid Build Coastguard Worker 438*635a8641SAndroid Build Coastguard Worker 439*635a8641SAndroid Build Coastguard Workerdef GetToolchainDir(): 440*635a8641SAndroid Build Coastguard Worker """Gets location information about the current toolchain (must have been 441*635a8641SAndroid Build Coastguard Worker previously updated by 'update'). This is used for the GN build.""" 442*635a8641SAndroid Build Coastguard Worker runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs() 443*635a8641SAndroid Build Coastguard Worker win_sdk_dir = SetEnvironmentAndGetSDKDir() 444*635a8641SAndroid Build Coastguard Worker 445*635a8641SAndroid Build Coastguard Worker print('''vs_path = %s 446*635a8641SAndroid Build Coastguard Workersdk_path = %s 447*635a8641SAndroid Build Coastguard Workervs_version = %s 448*635a8641SAndroid Build Coastguard Workerwdk_dir = %s 449*635a8641SAndroid Build Coastguard Workerruntime_dirs = %s 450*635a8641SAndroid Build Coastguard Worker''' % ( 451*635a8641SAndroid Build Coastguard Worker ToGNString(NormalizePath(os.environ['GYP_MSVS_OVERRIDE_PATH'])), 452*635a8641SAndroid Build Coastguard Worker ToGNString(win_sdk_dir), 453*635a8641SAndroid Build Coastguard Worker ToGNString(GetVisualStudioVersion()), 454*635a8641SAndroid Build Coastguard Worker ToGNString(NormalizePath(os.environ.get('WDK_DIR', ''))), 455*635a8641SAndroid Build Coastguard Worker ToGNString(os.path.pathsep.join(runtime_dll_dirs or ['None'])))) 456*635a8641SAndroid Build Coastguard Worker 457*635a8641SAndroid Build Coastguard Worker 458*635a8641SAndroid Build Coastguard Workerdef main(): 459*635a8641SAndroid Build Coastguard Worker commands = { 460*635a8641SAndroid Build Coastguard Worker 'update': Update, 461*635a8641SAndroid Build Coastguard Worker 'get_toolchain_dir': GetToolchainDir, 462*635a8641SAndroid Build Coastguard Worker 'copy_dlls': CopyDlls, 463*635a8641SAndroid Build Coastguard Worker } 464*635a8641SAndroid Build Coastguard Worker if len(sys.argv) < 2 or sys.argv[1] not in commands: 465*635a8641SAndroid Build Coastguard Worker print('Expected one of: %s' % ', '.join(commands), file=sys.stderr) 466*635a8641SAndroid Build Coastguard Worker return 1 467*635a8641SAndroid Build Coastguard Worker return commands[sys.argv[1]](*sys.argv[2:]) 468*635a8641SAndroid Build Coastguard Worker 469*635a8641SAndroid Build Coastguard Worker 470*635a8641SAndroid Build Coastguard Workerif __name__ == '__main__': 471*635a8641SAndroid Build Coastguard Worker sys.exit(main()) 472