Roll src/third_party/WebKit f007c95:0171005 (svn 185074:185088)
[chromium-blink-merge.git] / build / vs_toolchain.py
blobbdedd6fa8822f121da2687d338cbdf3f58140575
1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 import json
6 import os
7 import pipes
8 import shutil
9 import subprocess
10 import sys
13 script_dir = os.path.dirname(os.path.realpath(__file__))
14 chrome_src = os.path.abspath(os.path.join(script_dir, os.pardir))
15 SRC_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
16 sys.path.insert(1, os.path.join(chrome_src, 'tools'))
17 sys.path.insert(0, os.path.join(chrome_src, 'tools', 'gyp', 'pylib'))
18 json_data_file = os.path.join(script_dir, 'win_toolchain.json')
21 import gyp
24 def SetEnvironmentAndGetRuntimeDllDirs():
25 """Sets up os.environ to use the depot_tools VS toolchain with gyp, and
26 returns the location of the VS runtime DLLs so they can be copied into
27 the output directory after gyp generation.
28 """
29 vs2013_runtime_dll_dirs = None
30 depot_tools_win_toolchain = \
31 bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
32 if sys.platform in ('win32', 'cygwin') and depot_tools_win_toolchain:
33 if not os.path.exists(json_data_file):
34 Update()
35 with open(json_data_file, 'r') as tempf:
36 toolchain_data = json.load(tempf)
38 toolchain = toolchain_data['path']
39 version = toolchain_data['version']
40 version_is_pro = version[-1] != 'e'
41 win8sdk = toolchain_data['win8sdk']
42 wdk = toolchain_data['wdk']
43 # TODO(scottmg): The order unfortunately matters in these. They should be
44 # split into separate keys for x86 and x64. (See CopyVsRuntimeDlls call
45 # below). http://crbug.com/345992
46 vs2013_runtime_dll_dirs = toolchain_data['runtime_dirs']
48 os.environ['GYP_MSVS_OVERRIDE_PATH'] = toolchain
49 os.environ['GYP_MSVS_VERSION'] = version
50 # We need to make sure windows_sdk_path is set to the automated
51 # toolchain values in GYP_DEFINES, but don't want to override any
52 # otheroptions.express
53 # values there.
54 gyp_defines_dict = gyp.NameValueListToDict(gyp.ShlexEnv('GYP_DEFINES'))
55 gyp_defines_dict['windows_sdk_path'] = win8sdk
56 os.environ['GYP_DEFINES'] = ' '.join('%s=%s' % (k, pipes.quote(str(v)))
57 for k, v in gyp_defines_dict.iteritems())
58 os.environ['WINDOWSSDKDIR'] = win8sdk
59 os.environ['WDK_DIR'] = wdk
60 # Include the VS runtime in the PATH in case it's not machine-installed.
61 runtime_path = ';'.join(vs2013_runtime_dll_dirs)
62 os.environ['PATH'] = runtime_path + ';' + os.environ['PATH']
63 return vs2013_runtime_dll_dirs
66 def CopyVsRuntimeDlls(output_dir, runtime_dirs):
67 """Copies the VS runtime DLLs from the given |runtime_dirs| to the output
68 directory so that even if not system-installed, built binaries are likely to
69 be able to run.
71 This needs to be run after gyp has been run so that the expected target
72 output directories are already created.
73 """
74 assert sys.platform.startswith(('win32', 'cygwin'))
76 def copy_runtime_impl(target, source):
77 """Copy |source| to |target| if it doesn't already exist or if it need to be
78 updated.
79 """
80 if (os.path.isdir(os.path.dirname(target)) and
81 (not os.path.isfile(target) or
82 os.stat(target).st_mtime != os.stat(source).st_mtime)):
83 print 'Copying %s to %s...' % (source, target)
84 if os.path.exists(target):
85 os.unlink(target)
86 shutil.copy2(source, target)
88 def copy_runtime(target_dir, source_dir, dll_pattern):
89 """Copy both the msvcr and msvcp runtime DLLs, only if the target doesn't
90 exist, but the target directory does exist."""
91 for which in ('p', 'r'):
92 dll = dll_pattern % which
93 target = os.path.join(target_dir, dll)
94 source = os.path.join(source_dir, dll)
95 copy_runtime_impl(target, source)
97 x86, x64 = runtime_dirs
98 out_debug = os.path.join(output_dir, 'Debug')
99 out_debug_nacl64 = os.path.join(output_dir, 'Debug', 'x64')
100 out_release = os.path.join(output_dir, 'Release')
101 out_release_nacl64 = os.path.join(output_dir, 'Release', 'x64')
102 out_debug_x64 = os.path.join(output_dir, 'Debug_x64')
103 out_release_x64 = os.path.join(output_dir, 'Release_x64')
105 if os.path.exists(out_debug) and not os.path.exists(out_debug_nacl64):
106 os.makedirs(out_debug_nacl64)
107 if os.path.exists(out_release) and not os.path.exists(out_release_nacl64):
108 os.makedirs(out_release_nacl64)
109 copy_runtime(out_debug, x86, 'msvc%s120d.dll')
110 copy_runtime(out_release, x86, 'msvc%s120.dll')
111 copy_runtime(out_debug_x64, x64, 'msvc%s120d.dll')
112 copy_runtime(out_release_x64, x64, 'msvc%s120.dll')
113 copy_runtime(out_debug_nacl64, x64, 'msvc%s120d.dll')
114 copy_runtime(out_release_nacl64, x64, 'msvc%s120.dll')
116 # Copy the PGO runtime library to the release directories.
117 if os.environ.get('GYP_MSVS_OVERRIDE_PATH'):
118 pgo_x86_runtime_dir = os.path.join(os.environ.get('GYP_MSVS_OVERRIDE_PATH'),
119 'VC', 'bin')
120 pgo_x64_runtime_dir = os.path.join(pgo_x86_runtime_dir, 'amd64')
121 pgo_runtime_dll = 'pgort120.dll'
122 source_x86 = os.path.join(pgo_x86_runtime_dir, pgo_runtime_dll)
123 if os.path.exists(source_x86):
124 copy_runtime_impl(os.path.join(out_release, pgo_runtime_dll), source_x86)
125 source_x64 = os.path.join(pgo_x64_runtime_dir, pgo_runtime_dll)
126 if os.path.exists(source_x64):
127 copy_runtime_impl(os.path.join(out_release_x64, pgo_runtime_dll),
128 source_x64)
131 def _GetDesiredVsToolchainHashes():
132 """Load a list of SHA1s corresponding to the toolchains that we want installed
133 to build with."""
134 sha1path = os.path.join(script_dir,
135 '..', 'buildtools', 'toolchain_vs2013.hash')
136 with open(sha1path, 'rb') as f:
137 return f.read().strip().splitlines()
140 def Update():
141 """Requests an update of the toolchain to the specific hashes we have at
142 this revision. The update outputs a .json of the various configuration
143 information required to pass to gyp which we use in |GetToolchainDir()|.
145 depot_tools_win_toolchain = \
146 bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
147 if sys.platform in ('win32', 'cygwin') and depot_tools_win_toolchain:
148 import find_depot_tools
149 depot_tools_path = find_depot_tools.add_depot_tools_to_path()
150 json_data_file = os.path.join(script_dir, 'win_toolchain.json')
151 get_toolchain_args = [
152 sys.executable,
153 os.path.join(depot_tools_path,
154 'win_toolchain',
155 'get_toolchain_if_necessary.py'),
156 '--output-json', json_data_file,
157 ] + _GetDesiredVsToolchainHashes()
158 subprocess.check_call(get_toolchain_args)
160 return 0
163 def GetToolchainDir():
164 """Gets location information about the current toolchain (must have been
165 previously updated by 'update'). This is used for the GN build."""
166 SetEnvironmentAndGetRuntimeDllDirs()
168 # If WINDOWSSDKDIR is not set, search the default SDK path and set it.
169 if not 'WINDOWSSDKDIR' in os.environ:
170 default_sdk_path = 'C:\\Program Files (x86)\\Windows Kits\\8.0'
171 if os.path.isdir(default_sdk_path):
172 os.environ['WINDOWSSDKDIR'] = default_sdk_path
174 print '''vs_path = "%s"
175 sdk_path = "%s"
176 vs_version = "%s"
177 wdk_dir = "%s"
178 ''' % (
179 os.environ['GYP_MSVS_OVERRIDE_PATH'],
180 os.environ['WINDOWSSDKDIR'],
181 os.environ['GYP_MSVS_VERSION'],
182 os.environ.get('WDK_DIR', ''))
185 def main():
186 if not sys.platform.startswith(('win32', 'cygwin')):
187 return 0
188 commands = {
189 'update': Update,
190 'get_toolchain_dir': GetToolchainDir,
191 # TODO(scottmg): Add copy_dlls for GN builds (gyp_chromium calls
192 # CopyVsRuntimeDlls via import, currently).
194 if len(sys.argv) < 2 or sys.argv[1] not in commands:
195 print >>sys.stderr, 'Expected one of: %s' % ', '.join(commands)
196 return 1
197 return commands[sys.argv[1]]()
200 if __name__ == '__main__':
201 sys.exit(main())