Start opening HelpAndFeedback on SadTab suggestions link.
[chromium-blink-merge.git] / build / vs_toolchain.py
blob16f447755656bb5427097660553f8af28f8d74f0
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 win_sdk = toolchain_data.get('win_sdk')
41 if not win_sdk:
42 win_sdk = toolchain_data['win8sdk']
43 wdk = toolchain_data['wdk']
44 # TODO(scottmg): The order unfortunately matters in these. They should be
45 # split into separate keys for x86 and x64. (See CopyVsRuntimeDlls call
46 # below). http://crbug.com/345992
47 vs2013_runtime_dll_dirs = toolchain_data['runtime_dirs']
49 os.environ['GYP_MSVS_OVERRIDE_PATH'] = toolchain
50 os.environ['GYP_MSVS_VERSION'] = version
51 # We need to make sure windows_sdk_path is set to the automated
52 # toolchain values in GYP_DEFINES, but don't want to override any
53 # otheroptions.express
54 # values there.
55 gyp_defines_dict = gyp.NameValueListToDict(gyp.ShlexEnv('GYP_DEFINES'))
56 gyp_defines_dict['windows_sdk_path'] = win_sdk
57 os.environ['GYP_DEFINES'] = ' '.join('%s=%s' % (k, pipes.quote(str(v)))
58 for k, v in gyp_defines_dict.iteritems())
59 os.environ['WINDOWSSDKDIR'] = win_sdk
60 os.environ['WDK_DIR'] = wdk
61 # Include the VS runtime in the PATH in case it's not machine-installed.
62 runtime_path = ';'.join(vs2013_runtime_dll_dirs)
63 os.environ['PATH'] = runtime_path + ';' + os.environ['PATH']
64 return vs2013_runtime_dll_dirs
67 def _VersionNumber():
68 """Gets the standard version number ('120', '140', etc.) based on
69 GYP_MSVS_VERSION."""
70 if os.environ['GYP_MSVS_VERSION'] == '2013':
71 return '120'
72 elif os.environ['GYP_MSVS_VERSION'] == '2015':
73 return '140'
74 else:
75 raise ValueError('Unexpected GYP_MSVS_VERSION')
78 def _CopyRuntimeImpl(target, source):
79 """Copy |source| to |target| if it doesn't already exist or if it
80 needs to be updated.
81 """
82 if (os.path.isdir(os.path.dirname(target)) and
83 (not os.path.isfile(target) or
84 os.stat(target).st_mtime != os.stat(source).st_mtime)):
85 print 'Copying %s to %s...' % (source, target)
86 if os.path.exists(target):
87 os.unlink(target)
88 shutil.copy2(source, target)
91 def _CopyRuntime2013(target_dir, source_dir, dll_pattern):
92 """Copy both the msvcr and msvcp runtime DLLs, only if the target doesn't
93 exist, but the target directory does exist."""
94 for file_part in ('p', 'r'):
95 dll = dll_pattern % file_part
96 target = os.path.join(target_dir, dll)
97 source = os.path.join(source_dir, dll)
98 _CopyRuntimeImpl(target, source)
101 def _CopyRuntime2015(target_dir, source_dir, dll_pattern):
102 """Copy both the msvcp and vccorlib runtime DLLs, only if the target doesn't
103 exist, but the target directory does exist."""
104 for file_part in ('msvcp', 'vccorlib'):
105 dll = dll_pattern % file_part
106 target = os.path.join(target_dir, dll)
107 source = os.path.join(source_dir, dll)
108 _CopyRuntimeImpl(target, source)
111 def CopyVsRuntimeDlls(output_dir, runtime_dirs):
112 """Copies the VS runtime DLLs from the given |runtime_dirs| to the output
113 directory so that even if not system-installed, built binaries are likely to
114 be able to run.
116 This needs to be run after gyp has been run so that the expected target
117 output directories are already created.
119 assert sys.platform.startswith(('win32', 'cygwin'))
121 x86, x64 = runtime_dirs
122 out_debug = os.path.join(output_dir, 'Debug')
123 out_debug_nacl64 = os.path.join(output_dir, 'Debug', 'x64')
124 out_release = os.path.join(output_dir, 'Release')
125 out_release_nacl64 = os.path.join(output_dir, 'Release', 'x64')
126 out_debug_x64 = os.path.join(output_dir, 'Debug_x64')
127 out_release_x64 = os.path.join(output_dir, 'Release_x64')
129 if os.path.exists(out_debug) and not os.path.exists(out_debug_nacl64):
130 os.makedirs(out_debug_nacl64)
131 if os.path.exists(out_release) and not os.path.exists(out_release_nacl64):
132 os.makedirs(out_release_nacl64)
133 if os.environ.get('GYP_MSVS_VERSION') == '2015':
134 _CopyRuntime2015(out_debug, x86, '%s140d.dll')
135 _CopyRuntime2015(out_release, x86, '%s140.dll')
136 _CopyRuntime2015(out_debug_x64, x64, '%s140d.dll')
137 _CopyRuntime2015(out_release_x64, x64, '%s140.dll')
138 _CopyRuntime2015(out_debug_nacl64, x64, '%s140d.dll')
139 _CopyRuntime2015(out_release_nacl64, x64, '%s140.dll')
140 else:
141 # VS2013 is the default.
142 _CopyRuntime2013(out_debug, x86, 'msvc%s120d.dll')
143 _CopyRuntime2013(out_release, x86, 'msvc%s120.dll')
144 _CopyRuntime2013(out_debug_x64, x64, 'msvc%s120d.dll')
145 _CopyRuntime2013(out_release_x64, x64, 'msvc%s120.dll')
146 _CopyRuntime2013(out_debug_nacl64, x64, 'msvc%s120d.dll')
147 _CopyRuntime2013(out_release_nacl64, x64, 'msvc%s120.dll')
149 # Copy the PGO runtime library to the release directories.
150 if os.environ.get('GYP_MSVS_OVERRIDE_PATH'):
151 pgo_x86_runtime_dir = os.path.join(os.environ.get('GYP_MSVS_OVERRIDE_PATH'),
152 'VC', 'bin')
153 pgo_x64_runtime_dir = os.path.join(pgo_x86_runtime_dir, 'amd64')
154 pgo_runtime_dll = 'pgort' + _VersionNumber() + '.dll'
155 source_x86 = os.path.join(pgo_x86_runtime_dir, pgo_runtime_dll)
156 if os.path.exists(source_x86):
157 _CopyRuntimeImpl(os.path.join(out_release, pgo_runtime_dll), source_x86)
158 source_x64 = os.path.join(pgo_x64_runtime_dir, pgo_runtime_dll)
159 if os.path.exists(source_x64):
160 _CopyRuntimeImpl(os.path.join(out_release_x64, pgo_runtime_dll),
161 source_x64)
164 def CopyDlls(target_dir, configuration, target_cpu):
165 """Copy the VS runtime DLLs into the requested directory as needed.
167 configuration is one of 'Debug' or 'Release'.
168 target_cpu is one of 'x86' or 'x64'.
170 The debug configuration gets both the debug and release DLLs; the
171 release config only the latter.
173 vs2013_runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
174 if not vs2013_runtime_dll_dirs:
175 return
177 x64_runtime, x86_runtime = vs2013_runtime_dll_dirs
178 runtime_dir = x64_runtime if target_cpu == 'x64' else x86_runtime
179 _CopyRuntime2013(
180 target_dir, runtime_dir, 'msvc%s' + _VersionNumber() + '.dll')
181 if configuration == 'Debug':
182 _CopyRuntime2013(
183 target_dir, runtime_dir, 'msvc%s' + _VersionNumber() + 'd.dll')
186 def _GetDesiredVsToolchainHashes():
187 """Load a list of SHA1s corresponding to the toolchains that we want installed
188 to build with."""
189 # TODO(scottmg): If explicitly set to VS2015 override hashes to the VS2015 RC
190 # toolchain. http://crbug.com/492774.
191 if os.environ.get('GYP_MSVS_VERSION') == '2015':
192 return ['40721575c85171cea5d7afe5ec17bd108a94796e']
193 else:
194 # Default to VS2013.
195 return ['ee7d718ec60c2dc5d255bbe325909c2021a7efef']
198 def Update():
199 """Requests an update of the toolchain to the specific hashes we have at
200 this revision. The update outputs a .json of the various configuration
201 information required to pass to gyp which we use in |GetToolchainDir()|.
203 depot_tools_win_toolchain = \
204 bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
205 if sys.platform in ('win32', 'cygwin') and depot_tools_win_toolchain:
206 import find_depot_tools
207 depot_tools_path = find_depot_tools.add_depot_tools_to_path()
208 get_toolchain_args = [
209 sys.executable,
210 os.path.join(depot_tools_path,
211 'win_toolchain',
212 'get_toolchain_if_necessary.py'),
213 '--output-json', json_data_file,
214 ] + _GetDesiredVsToolchainHashes()
215 subprocess.check_call(get_toolchain_args)
217 return 0
220 def GetToolchainDir():
221 """Gets location information about the current toolchain (must have been
222 previously updated by 'update'). This is used for the GN build."""
223 runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
225 # If WINDOWSSDKDIR is not set, search the default SDK path and set it.
226 if not 'WINDOWSSDKDIR' in os.environ:
227 default_sdk_path = 'C:\\Program Files (x86)\\Windows Kits\\8.1'
228 if os.path.isdir(default_sdk_path):
229 os.environ['WINDOWSSDKDIR'] = default_sdk_path
231 print '''vs_path = "%s"
232 sdk_path = "%s"
233 vs_version = "%s"
234 wdk_dir = "%s"
235 runtime_dirs = "%s"
236 ''' % (
237 os.environ['GYP_MSVS_OVERRIDE_PATH'],
238 os.environ['WINDOWSSDKDIR'],
239 os.environ['GYP_MSVS_VERSION'],
240 os.environ.get('WDK_DIR', ''),
241 ';'.join(runtime_dll_dirs or ['None']))
244 def main():
245 if not sys.platform.startswith(('win32', 'cygwin')):
246 return 0
247 commands = {
248 'update': Update,
249 'get_toolchain_dir': GetToolchainDir,
250 'copy_dlls': CopyDlls,
252 if len(sys.argv) < 2 or sys.argv[1] not in commands:
253 print >>sys.stderr, 'Expected one of: %s' % ', '.join(commands)
254 return 1
255 return commands[sys.argv[1]](*sys.argv[2:])
258 if __name__ == '__main__':
259 sys.exit(main())