OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2013 The Chromium Authors. All rights reserved. | 2 # Copyright 2013 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Downloads and unpacks a toolchain for building on Windows. The contents are | 6 """Downloads and unpacks a toolchain for building on Windows. The contents are |
7 matched by sha1 which will be updated when the toolchain is updated. | 7 matched by sha1 which will be updated when the toolchain is updated. |
8 | 8 |
9 Having a toolchain script in depot_tools means that it's not versioned | 9 Having a toolchain script in depot_tools means that it's not versioned |
10 directly with the source code. That is, if the toolchain is upgraded, but | 10 directly with the source code. That is, if the toolchain is upgraded, but |
(...skipping 12 matching lines...) Expand all Loading... |
23 to do the main work. It is expected that toolchain2013.py will always be able | 23 to do the main work. It is expected that toolchain2013.py will always be able |
24 to acquire/build the most current revision of a VS2013-based toolchain. In the | 24 to acquire/build the most current revision of a VS2013-based toolchain. In the |
25 future when a hypothetical VS2015 is released, the 2013 script will be | 25 future when a hypothetical VS2015 is released, the 2013 script will be |
26 maintained, and a new 2015 script would be added. | 26 maintained, and a new 2015 script would be added. |
27 """ | 27 """ |
28 | 28 |
29 import hashlib | 29 import hashlib |
30 import json | 30 import json |
31 import optparse | 31 import optparse |
32 import os | 32 import os |
| 33 import platform |
| 34 import re |
33 import shutil | 35 import shutil |
34 import subprocess | 36 import subprocess |
35 import sys | 37 import sys |
36 import tempfile | 38 import tempfile |
37 import time | 39 import time |
38 import zipfile | 40 import zipfile |
39 | 41 |
40 | 42 |
41 BASEDIR = os.path.dirname(os.path.abspath(__file__)) | 43 BASEDIR = os.path.dirname(os.path.abspath(__file__)) |
42 DEPOT_TOOLS_PATH = os.path.join(BASEDIR, '..') | 44 DEPOT_TOOLS_PATH = os.path.join(BASEDIR, '..') |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 else: | 212 else: |
211 temp_dir, local_zip = DownloadUsingGsutil(tree_sha1 + '.zip') | 213 temp_dir, local_zip = DownloadUsingGsutil(tree_sha1 + '.zip') |
212 sys.stdout.write('Extracting %s...\n' % local_zip) | 214 sys.stdout.write('Extracting %s...\n' % local_zip) |
213 sys.stdout.flush() | 215 sys.stdout.flush() |
214 with zipfile.ZipFile(local_zip, 'r', zipfile.ZIP_DEFLATED, True) as zf: | 216 with zipfile.ZipFile(local_zip, 'r', zipfile.ZIP_DEFLATED, True) as zf: |
215 zf.extractall(target_dir) | 217 zf.extractall(target_dir) |
216 if temp_dir: | 218 if temp_dir: |
217 RmDir(temp_dir) | 219 RmDir(temp_dir) |
218 | 220 |
219 | 221 |
| 222 def GetInstallerName(): |
| 223 """Return the name of the Windows 10 Universal C Runtime installer for the |
| 224 current platform, or None if installer is not needed or not applicable. |
| 225 The registry has to be used instead of sys.getwindowsversion() because |
| 226 Python 2.7 is only manifested as being compatible up to Windows 8, so the |
| 227 version APIs helpfully return a maximum of 6.2 (Windows 8). |
| 228 """ |
| 229 ver_re = re.compile('.*REG_SZ * (\d+)\.(\d+)') |
| 230 key_name = '"HKLM\Software\Microsoft\Windows NT\CurrentVersion"' |
| 231 output = subprocess.check_output('reg query %s /v CurrentVersion' % key_name) |
| 232 match = ver_re.match(output.replace('\n', ' ')) |
| 233 if match.groups() == ('6', '1'): |
| 234 # Windows 7 and Windows Server 2008 R2 |
| 235 return 'Windows6.1-KB2999226-x64.msu' |
| 236 elif match.groups() == ('6', '2'): |
| 237 # Windows 8 and Windows Server 2012 |
| 238 return 'Windows8-RT-KB2999226-x64.msu' |
| 239 elif match.groups() == ('6', '3'): |
| 240 # Windows 8.1 and Windows Server 2012 R2 |
| 241 return 'Windows8.1-KB2999226-x64.msu' |
| 242 else: |
| 243 # Windows 10 or higher assumed |
| 244 return None |
| 245 |
| 246 |
| 247 def InstallUniversalCRTIfNeeded(abs_target_dir): |
| 248 installer_name = GetInstallerName() |
| 249 if not installer_name: |
| 250 # Assumed to be Windows 10+ so nothing to do |
| 251 return |
| 252 |
| 253 bitness = platform.architecture()[0] |
| 254 # When running 64-bit python the x64 DLLs will be in System32 |
| 255 x64_path = 'System32' if bitness == '64bit' else 'Sysnative' |
| 256 x64_path = os.path.join(r'C:\Windows', x64_path) |
| 257 sample_crt_file = os.path.join(x64_path, 'api-ms-win-crt-math-l1-1-0.dll') |
| 258 |
| 259 if os.path.exists(sample_crt_file): |
| 260 # Nothing to do. |
| 261 return |
| 262 |
| 263 print ('%s does not exist - installing Windows 10 Universal C Runtime' % |
| 264 sample_crt_file) |
| 265 |
| 266 installer = os.path.join(abs_target_dir, "installers", installer_name) |
| 267 command = r'wusa.exe /quiet "%s"' % installer |
| 268 print 'Running %s' % command |
| 269 |
| 270 try: |
| 271 subprocess.check_call(command) |
| 272 except WindowsError as e: |
| 273 if e.winerror == 740: # The requested operation requires elevation |
| 274 print |
| 275 print '-'*80 |
| 276 print |
| 277 print 'Elevation required. You must manually install this update:' |
| 278 print ' %s' % installer |
| 279 print |
| 280 print '-'*80 |
| 281 print |
| 282 raise Exception('Elevation required. You must manually install %s' % |
| 283 installer) |
| 284 raise e |
| 285 |
| 286 |
220 def main(): | 287 def main(): |
221 parser = optparse.OptionParser(description=sys.modules[__name__].__doc__) | 288 parser = optparse.OptionParser(description=sys.modules[__name__].__doc__) |
222 parser.add_option('--output-json', metavar='FILE', | 289 parser.add_option('--output-json', metavar='FILE', |
223 help='write information about toolchain to FILE') | 290 help='write information about toolchain to FILE') |
224 parser.add_option('--force', action='store_true', | 291 parser.add_option('--force', action='store_true', |
225 help='force script to run on non-Windows hosts') | 292 help='force script to run on non-Windows hosts') |
226 options, args = parser.parse_args() | 293 options, args = parser.parse_args() |
227 | 294 |
228 if not (sys.platform.startswith(('cygwin', 'win32')) or options.force): | 295 if not (sys.platform.startswith(('cygwin', 'win32')) or options.force): |
229 return 0 | 296 return 0 |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 'Got wrong hash after pulling a new toolchain. ' | 391 'Got wrong hash after pulling a new toolchain. ' |
325 'Wanted one of \'%s\', got \'%s\'.' % ( | 392 'Wanted one of \'%s\', got \'%s\'.' % ( |
326 ', '.join(desired_hashes), current_hash)) | 393 ', '.join(desired_hashes), current_hash)) |
327 return 1 | 394 return 1 |
328 SaveTimestampsAndHash(target_dir, current_hash) | 395 SaveTimestampsAndHash(target_dir, current_hash) |
329 | 396 |
330 if options.output_json: | 397 if options.output_json: |
331 shutil.copyfile(os.path.join(target_dir, '..', 'data.json'), | 398 shutil.copyfile(os.path.join(target_dir, '..', 'data.json'), |
332 options.output_json) | 399 options.output_json) |
333 | 400 |
| 401 InstallUniversalCRTIfNeeded(abs_target_dir) |
| 402 |
334 return 0 | 403 return 0 |
335 | 404 |
336 | 405 |
337 if __name__ == '__main__': | 406 if __name__ == '__main__': |
338 sys.exit(main()) | 407 sys.exit(main()) |
OLD | NEW |