18from gn_helpers
import ToGNString
42TOOLCHAIN_HASH =
'27370823e7'
43SDK_VERSION =
'10.0.22621.0'
45script_dir = os.path.dirname(os.path.realpath(__file__))
46json_data_file = os.path.join(script_dir,
'win_toolchain.json')
51MSVS_VERSIONS = collections.OrderedDict([
59MSVC_TOOLSET_VERSION = {
66 """Returns True if running on a Windows host (including under cygwin)."""
67 return sys.platform
in (
'win32',
'cygwin')
70 """Sets up os.environ to use the depot_tools VS toolchain with gyp, and
71 returns the location of the VC runtime DLLs so they can be copied into
72 the output directory after gyp generation.
74 Return value is [x64path, x86path,
'Arm64Unused']
or None. arm64path
is
75 generated separately because there are multiple folders
for the arm64 VC
78 vs_runtime_dll_dirs = None
79 depot_tools_win_toolchain = \
80 bool(
int(os.environ.get(
'DEPOT_TOOLS_WIN_TOOLCHAIN',
'1')))
83 if ((_HostIsWindows()
or os.path.exists(json_data_file))
84 and depot_tools_win_toolchain):
86 if len(sys.argv) > 1
and sys.argv[1] ==
'update':
89 update_result =
Update(no_download=
True)
90 if update_result != 0:
91 raise Exception(
'Failed to update, error code %d.' % update_result)
92 with open(json_data_file,
'r')
as tempf:
93 toolchain_data = json.load(tempf)
95 toolchain = toolchain_data[
'path']
96 version = toolchain_data[
'version']
97 win_sdk = toolchain_data.get(
'win_sdk')
98 wdk = toolchain_data[
'wdk']
102 vs_runtime_dll_dirs = toolchain_data[
'runtime_dirs']
106 if len(vs_runtime_dll_dirs) == 2:
107 vs_runtime_dll_dirs.append(
'Arm64Unused')
109 os.environ[
'GYP_MSVS_OVERRIDE_PATH'] = toolchain
111 os.environ[
'WINDOWSSDKDIR'] = win_sdk
112 os.environ[
'WDK_DIR'] = wdk
114 runtime_path = os.path.pathsep.join(vs_runtime_dll_dirs)
115 os.environ[
'PATH'] = runtime_path + os.path.pathsep + os.environ[
'PATH']
116 elif sys.platform ==
'win32' and not depot_tools_win_toolchain:
117 if not 'GYP_MSVS_OVERRIDE_PATH' in os.environ:
124 bitness = platform.architecture()[0]
128 x64_path =
'System32' if bitness ==
'64bit' else 'Sysnative'
129 x64_path = os.path.join(os.path.expandvars(
'%windir%'), x64_path)
130 vs_runtime_dll_dirs = [x64_path,
131 os.path.join(os.path.expandvars(
'%windir%'),
135 return vs_runtime_dll_dirs
138def _RegistryGetValueUsingWinReg(key, value):
139 """Use the _winreg module to obtain the value of a registry key.
142 key: The registry key.
143 value: The particular registry value to read.
145 contents of the registry key's value, or None on failure. Throws
146 ImportError if _winreg
is unavailable.
150 root, subkey = key.split(
'\\', 1)
151 assert root ==
'HKLM'
152 with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, subkey)
as hkey:
153 return _winreg.QueryValueEx(hkey, value)[0]
158def _RegistryGetValue(key, value):
160 return _RegistryGetValueUsingWinReg(key, value)
162 raise Exception(
'The python library _winreg not found.')
166 """Return best available version of Visual Studio.
168 supported_versions = list(MSVS_VERSIONS.keys())
171 if bool(
int(os.environ.get(
'DEPOT_TOOLS_WIN_TOOLCHAIN',
'1'))):
172 return supported_versions[0]
175 supported_versions_str =
', '.
join(
'{} ({})'.
format(v,k)
176 for k,v
in MSVS_VERSIONS.items())
177 available_versions = []
178 for version
in supported_versions:
183 path = os.environ.get(
'vs%s_install' % version)
184 if path
and os.path.exists(path):
185 available_versions.append(version)
188 if version >=
'2022':
189 program_files_path_variable =
'%ProgramFiles%'
191 program_files_path_variable =
'%ProgramFiles(x86)%'
192 path = os.path.expandvars(program_files_path_variable +
193 '/Microsoft Visual Studio/%s' % version)
195 os.path.exists(os.path.join(path, edition))
196 for edition
in (
'Enterprise',
'Professional',
'Community',
'Preview',
198 available_versions.append(version)
201 if not available_versions:
202 raise Exception(
'No supported Visual Studio can be found.'
203 ' Supported versions are: %s.' % supported_versions_str)
204 return available_versions[0]
208 """Return path to the installed Visual Studio.
219 if version_as_year >=
'2022':
220 program_files_path_variable =
'%ProgramFiles%'
222 program_files_path_variable =
'%ProgramFiles(x86)%'
223 for path
in (os.environ.get(
'vs%s_install' % version_as_year),
224 os.path.expandvars(program_files_path_variable +
225 '/Microsoft Visual Studio/%s/Enterprise' %
227 os.path.expandvars(program_files_path_variable +
228 '/Microsoft Visual Studio/%s/Professional' %
230 os.path.expandvars(program_files_path_variable +
231 '/Microsoft Visual Studio/%s/Community' %
233 os.path.expandvars(program_files_path_variable +
234 '/Microsoft Visual Studio/%s/Preview' %
236 os.path.expandvars(program_files_path_variable +
237 '/Microsoft Visual Studio/%s/BuildTools' %
239 if path
and os.path.exists(path):
242 raise Exception(
'Visual Studio Version %s not found.' % version_as_year)
245def _CopyRuntimeImpl(target, source, verbose=True):
246 """Copy |source| to |target| if it doesn't already exist or if it needs to be
247 updated (comparing last modified time as an approximate float match
as for
248 some reason the values tend to differ by ~1e-07 despite being copies of the
249 same file... https://crbug.com/603603).
251 if (os.path.isdir(os.path.dirname(target))
and
252 (
not os.path.isfile(target)
or
253 abs(os.stat(target).st_mtime - os.stat(source).st_mtime) >= 0.01)):
255 print(
'Copying %s to %s...' % (source, target))
256 if os.path.exists(target):
259 os.chmod(target, stat.S_IWRITE | stat.S_IREAD)
261 shutil.copy2(source, target)
264 os.chmod(target, stat.S_IWRITE | stat.S_IREAD)
266def _SortByHighestVersionNumberFirst(list_of_str_versions):
267 """This sorts |list_of_str_versions| according to version number rules
268 so that version "1.12" is higher than version
"1.9". Does
not work
269 with non-numeric versions like 1.4.a8 which will be higher than
270 1.4.a12. It does handle the versions being embedded
in file paths.
272 def to_int_if_int(x):
278 def to_number_sequence(x):
279 part_sequence = re.split(
r'[\\/\.]', x)
280 return [to_int_if_int(x)
for x
in part_sequence]
282 list_of_str_versions.sort(key=to_number_sequence, reverse=
True)
285def _CopyUCRTRuntime(target_dir, source_dir, target_cpu, suffix):
286 """Copy both the msvcp and vccorlib runtime DLLs, only if the target doesn't
287 exist, but the target directory does exist."""
288 if target_cpu ==
'arm64':
293 if suffix.startswith(
'.'):
294 vc_toolset_dir =
'Microsoft.{}.CRT' \
296 source_dir = os.path.join(vc_redist_root,
297 'arm64', vc_toolset_dir)
299 vc_toolset_dir =
'Microsoft.{}.DebugCRT' \
301 source_dir = os.path.join(vc_redist_root,
'debug_nonredist',
302 'arm64', vc_toolset_dir)
303 file_parts = (
'msvcp140',
'vccorlib140',
'vcruntime140')
305 file_parts = file_parts + (
'vcruntime140_1', )
306 for file_part
in file_parts:
307 dll = file_part + suffix
308 target = os.path.join(target_dir, dll)
309 source = os.path.join(source_dir, dll)
310 _CopyRuntimeImpl(target, source)
313 if not suffix.startswith(
'.'):
314 win_sdk_dir = os.path.normpath(
317 os.path.expandvars(
'%ProgramFiles(x86)%'
318 '\\Windows Kits\\10')))
321 sdk_bin_root = os.path.join(win_sdk_dir,
'bin')
322 sdk_bin_sub_dirs = glob.glob(os.path.join(sdk_bin_root,
'10.*'))
324 _SortByHighestVersionNumberFirst(sdk_bin_sub_dirs)
325 for directory
in sdk_bin_sub_dirs:
326 sdk_redist_root_version = os.path.join(sdk_bin_root, directory)
327 if not os.path.isdir(sdk_redist_root_version):
329 source_dir = os.path.join(sdk_redist_root_version, target_cpu,
'ucrt')
330 if not os.path.isdir(source_dir):
333 _CopyRuntimeImpl(os.path.join(target_dir,
'ucrtbase' + suffix),
334 os.path.join(source_dir,
'ucrtbase' + suffix))
338 """Find the most recent Tools or Redist or other directory in an MSVC install.
339 Typical results are {toolchain_root}/VC/{component}/MSVC/{x.y.z}. The {x.y.z}
340 version number part changes frequently so the highest version number found is
345 assert (
'GYP_MSVS_OVERRIDE_PATH' in os.environ)
346 vc_component_msvc_root = os.path.join(os.environ[
'GYP_MSVS_OVERRIDE_PATH'],
347 'VC', component,
'MSVC')
348 vc_component_msvc_contents = glob.glob(
349 os.path.join(vc_component_msvc_root,
'14.*'))
351 _SortByHighestVersionNumberFirst(vc_component_msvc_contents)
352 for directory
in vc_component_msvc_contents:
353 if os.path.isdir(directory):
355 raise Exception(
'Unable to find the VC %s directory.' % component)
359 """In >=VS2017, Redist binaries are located in
360 {toolchain_root}/VC/Redist/MSVC/{x.y.z}/{target_cpu}/.
362 This returns the '{toolchain_root}/VC/Redist/MSVC/{x.y.z}/' path.
367def _CopyRuntime(target_dir, source_dir, target_cpu, debug):
368 """Copy the VS runtime DLLs, only if the target doesn't exist, but the target
369 directory does exist. Handles VS 2015, 2017 and 2019.
"""
370 suffix = 'd.dll' if debug
else '.dll'
372 _CopyUCRTRuntime(target_dir, source_dir, target_cpu, suffix)
375def CopyDlls(target_dir, configuration, target_cpu):
376 """Copy the VS runtime DLLs into the requested directory as needed.
378 configuration is one of
'Debug' or 'Release'.
379 target_cpu
is one of
'x86',
'x64' or 'arm64'.
381 The debug configuration gets both the debug
and release DLLs; the
382 release config only the latter.
385 if not vs_runtime_dll_dirs:
388 x64_runtime, x86_runtime, arm64_runtime = vs_runtime_dll_dirs
389 if target_cpu ==
'x64':
390 runtime_dir = x64_runtime
391 elif target_cpu ==
'x86':
392 runtime_dir = x86_runtime
393 elif target_cpu ==
'arm64':
394 runtime_dir = arm64_runtime
396 raise Exception(
'Unknown target_cpu: ' + target_cpu)
397 _CopyRuntime(target_dir, runtime_dir, target_cpu, debug=
False)
398 if configuration ==
'Debug':
399 _CopyRuntime(target_dir, runtime_dir, target_cpu, debug=
True)
400 _CopyDebugger(target_dir, target_cpu)
401 if target_cpu ==
'arm64':
402 target_dir = os.path.join(target_dir,
'win_clang_x64')
404 runtime_dir = x64_runtime
405 os.makedirs(target_dir, exist_ok=
True)
406 _CopyRuntime(target_dir, runtime_dir, target_cpu, debug=
False)
407 if configuration ==
'Debug':
408 _CopyRuntime(target_dir, runtime_dir, target_cpu, debug=
True)
409 _CopyDebugger(target_dir, target_cpu)
412def _CopyDebugger(target_dir, target_cpu):
413 """Copy dbghelp.dll, dbgcore.dll, and msdia140.dll into the requested
416 target_cpu is one of
'x86',
'x64' or 'arm64'.
418 dbghelp.dll
is used when Chrome needs to symbolize stacks. Copying this file
419 from the SDK directory avoids using the system copy of dbghelp.dll which then
420 ensures compatibility
with recent debug information formats, such
as
421 large-page PDBs. Note that
for these DLLs to be deployed to swarming bots they
422 also need to be listed
in group(
"runtime_libs").
424 dbgcore.dll
is needed when using some functions
from dbghelp.dll (like
427 msdia140.dll
is needed
for tools like symupload.exe
and dump_syms.exe.
435 debug_files = [(
'dbghelp.dll',
False), (
'dbgcore.dll',
True)]
436 for debug_file, is_optional
in debug_files:
437 full_path = os.path.join(win_sdk_dir,
'Debuggers', target_cpu, debug_file)
438 if not os.path.exists(full_path):
442 raise Exception(
'%s not found in "%s"\r\nYou must install '
443 'Windows 10 SDK version %s including the '
444 '"Debugging Tools for Windows" feature.' %
445 (debug_file, full_path, SDK_VERSION))
446 target_path = os.path.join(target_dir, debug_file)
447 _CopyRuntimeImpl(target_path, full_path)
451 dia_path = os.path.join(
NormalizePath(os.environ[
'GYP_MSVS_OVERRIDE_PATH']),
452 'DIA SDK',
'bin',
'amd64',
'msdia140.dll')
453 _CopyRuntimeImpl(os.path.join(target_dir,
'msdia140.dll'), dia_path)
456def _GetDesiredVsToolchainHashes():
457 """Load a list of SHA1s corresponding to the toolchains that we want installed
461 toolchain_hash_mapping_key =
'GYP_MSVS_HASH_%s' % TOOLCHAIN_HASH
462 return [os.environ.get(toolchain_hash_mapping_key, TOOLCHAIN_HASH)]
466 """Check if the toolchain should be upgraded."""
467 if not os.path.exists(json_data_file):
469 with open(json_data_file,
'r')
as tempf:
470 toolchain_data = json.load(tempf)
471 version = toolchain_data[
'version']
475 return version != env_version
478def Update(force=False, no_download=False):
479 """Requests an update of the toolchain to the specific hashes we have at
480 this revision. The update outputs a .json of the various configuration
481 information required to pass to gyp which we use
in |
GetToolchainDir()|.
482 If no_download
is true then the toolchain will be configured
if present but
483 will
not be downloaded.
485 if force !=
False and force !=
'--force':
486 print(
'Unknown parameter "%s"' % force, file=sys.stderr)
488 if force ==
'--force' or os.path.exists(json_data_file):
491 depot_tools_win_toolchain = \
492 bool(
int(os.environ.get(
'DEPOT_TOOLS_WIN_TOOLCHAIN',
'1')))
493 if (_HostIsWindows()
or force)
and depot_tools_win_toolchain:
494 import find_depot_tools
501 toolchain_dir = os.path.join(depot_tools_path,
'win_toolchain',
'vs_files')
504 if sys.platform.startswith(
'linux')
and not os.path.ismount(toolchain_dir):
505 ciopfs = shutil.which(
'ciopfs')
508 ciopfs = os.path.join(script_dir,
'ciopfs')
509 if not os.path.isdir(toolchain_dir):
510 os.mkdir(toolchain_dir)
511 if not os.path.isdir(toolchain_dir +
'.ciopfs'):
512 os.mkdir(toolchain_dir +
'.ciopfs')
517 subprocess.check_call([
518 ciopfs,
'-o',
'use_ino', toolchain_dir +
'.ciopfs', toolchain_dir])
523 toolchain_dir = os.path.join(os.getcwd(),
'sdk',
'win_toolchain')
524 get_toolchain_args = [
526 os.path.join(depot_tools_path,
528 'get_toolchain_if_necessary.py'),
529 '--output-json', json_data_file,
530 '--toolchain-dir', toolchain_dir,
531 ] + _GetDesiredVsToolchainHashes()
533 get_toolchain_args.append(
'--force')
535 get_toolchain_args.append(
'--no-download')
536 subprocess.check_call(get_toolchain_args)
542 while path.endswith(
'\\'):
548 """Gets location information about the current sdk (must have been
549 previously updated by 'update'). This
is used
for the GN build.
"""
553 if not 'WINDOWSSDKDIR' in os.environ:
554 default_sdk_path = os.path.expandvars(
'%ProgramFiles(x86)%'
555 '\\Windows Kits\\10')
556 if os.path.isdir(default_sdk_path):
557 os.environ[
'WINDOWSSDKDIR'] = default_sdk_path
563 """Gets location information about the current toolchain (must have been
564 previously updated by 'update'). This
is used
for the GN build.
"""
568 print('''vs_path = %s
575 os.environ[
'GYP_MSVS_OVERRIDE_PATH'])),
ToGNString(SDK_VERSION),
578 ToGNString(os.path.pathsep.join(runtime_dll_dirs
or [
'None']))))
584 'get_toolchain_dir': GetToolchainDir,
585 'copy_dlls': CopyDlls,
587 if len(sys.argv) < 2
or sys.argv[1]
not in commands:
588 print(
'Expected one of: %s' %
', '.
join(commands), file=sys.stderr)
590 return commands[sys.argv[1]](*sys.argv[2:])
593if __name__ ==
'__main__':
uint32_t uint32_t * format
def ToGNString(value, allow_dicts=True)
def print(*args, **kwargs)
SIN Vec< N, float > abs(const Vec< N, float > &x)
SIT bool any(const Vec< 1, T > &x)
static SkString join(const CommandLineFlags::StringArray &)