Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 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 """This script is used to download prebuilt clang binaries. | 6 """This script is used to download prebuilt clang binaries. |
| 7 | 7 |
| 8 It is also used by package.py to build the prebuilt clang binaries.""" | 8 It is also used by package.py to build the prebuilt clang binaries.""" |
| 9 | 9 |
| 10 import argparse | 10 import argparse |
| 11 import distutils.spawn | 11 import distutils.spawn |
| 12 import glob | 12 import glob |
| 13 import os | 13 import os |
| 14 import pipes | 14 import pipes |
| 15 import re | 15 import re |
| 16 import shutil | 16 import shutil |
| 17 import subprocess | 17 import subprocess |
| 18 import stat | 18 import stat |
| 19 import sys | 19 import sys |
| 20 import tarfile | 20 import tarfile |
| 21 import tempfile | 21 import tempfile |
| 22 import time | 22 import time |
| 23 import urllib2 | |
| 24 import zipfile | 23 import zipfile |
| 25 | 24 |
| 26 # Do NOT CHANGE this if you don't know what you're doing -- see | 25 # Do NOT CHANGE this if you don't know what you're doing -- see |
| 27 # https://chromium.googlesource.com/chromium/src/+/master/docs/updating_clang.md | 26 # https://chromium.googlesource.com/chromium/src/+/master/docs/updating_clang.md |
| 28 # Reverting problematic clang rolls is safe, though. | 27 # Reverting problematic clang rolls is safe, though. |
| 29 CLANG_REVISION = '259396' | 28 CLANG_REVISION = '259396' |
| 30 | 29 |
| 31 use_head_revision = 'LLVM_FORCE_HEAD_REVISION' in os.environ | 30 use_head_revision = 'LLVM_FORCE_HEAD_REVISION' in os.environ |
| 32 if use_head_revision: | 31 if use_head_revision: |
| 33 CLANG_REVISION = 'HEAD' | 32 CLANG_REVISION = 'HEAD' |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 62 LIBCXXABI_DIR = os.path.join(LLVM_DIR, 'projects', 'libcxxabi') | 61 LIBCXXABI_DIR = os.path.join(LLVM_DIR, 'projects', 'libcxxabi') |
| 63 LLVM_BUILD_TOOLS_DIR = os.path.abspath( | 62 LLVM_BUILD_TOOLS_DIR = os.path.abspath( |
| 64 os.path.join(LLVM_DIR, '..', 'llvm-build-tools')) | 63 os.path.join(LLVM_DIR, '..', 'llvm-build-tools')) |
| 65 STAMP_FILE = os.path.normpath( | 64 STAMP_FILE = os.path.normpath( |
| 66 os.path.join(LLVM_DIR, '..', 'llvm-build', 'cr_build_revision')) | 65 os.path.join(LLVM_DIR, '..', 'llvm-build', 'cr_build_revision')) |
| 67 BINUTILS_DIR = os.path.join(THIRD_PARTY_DIR, 'binutils') | 66 BINUTILS_DIR = os.path.join(THIRD_PARTY_DIR, 'binutils') |
| 68 VERSION = '3.9.0' | 67 VERSION = '3.9.0' |
| 69 ANDROID_NDK_DIR = os.path.join( | 68 ANDROID_NDK_DIR = os.path.join( |
| 70 CHROMIUM_DIR, 'third_party', 'android_tools', 'ndk') | 69 CHROMIUM_DIR, 'third_party', 'android_tools', 'ndk') |
| 71 | 70 |
| 72 # URL for pre-built binaries. | 71 sys.path.insert(0, os.path.join(CHROMIUM_DIR, 'build')) |
| 73 CDS_URL = 'https://commondatastorage.googleapis.com/chromium-browser-clang' | 72 import find_depot_tools |
| 73 DEPOT_PATH = find_depot_tools.add_depot_tools_to_path() | |
| 74 GSUTIL_PATH = os.path.join(DEPOT_PATH, 'gsutil.py') | |
| 75 | |
| 76 # Google Storage bucket where the pre-built binaries are kept. | |
| 77 CDS_BUCKET = 'gs://chromium-browser-clang' | |
| 74 | 78 |
| 75 LLVM_REPO_URL='https://llvm.org/svn/llvm-project' | 79 LLVM_REPO_URL='https://llvm.org/svn/llvm-project' |
| 76 if 'LLVM_REPO_URL' in os.environ: | 80 if 'LLVM_REPO_URL' in os.environ: |
| 77 LLVM_REPO_URL = os.environ['LLVM_REPO_URL'] | 81 LLVM_REPO_URL = os.environ['LLVM_REPO_URL'] |
| 78 | 82 |
| 79 | 83 |
| 80 def DownloadUrl(url, output_file): | 84 def DownloadFile(source, output_file): |
| 81 """Download url into output_file.""" | 85 """Download google storage source into output_file.""" |
| 82 CHUNK_SIZE = 4096 | |
| 83 TOTAL_DOTS = 10 | |
| 84 num_retries = 3 | 86 num_retries = 3 |
| 85 retry_wait_s = 5 # Doubled at each retry. | 87 retry_wait_s = 5 # Doubled at each retry. |
| 86 | 88 |
| 87 while True: | 89 while True: |
| 88 try: | 90 try: |
| 89 sys.stdout.write('Downloading %s ' % url) | 91 sys.stdout.write('Downloading %s ' % source) |
| 90 sys.stdout.flush() | 92 sys.stdout.flush() |
| 91 response = urllib2.urlopen(url) | 93 cmd = ['python', GSUTIL_PATH, 'cp', source, output_file] |
| 92 total_size = int(response.info().getheader('Content-Length').strip()) | 94 subprocess.check_call(cmd, stderr=open('/dev/null', 'w')) |
|
hans
2016/02/12 00:39:11
What does the error message look like for the user
Mostyn Bramley-Moore
2016/02/12 00:43:33
This is what I get on a throttled/blocked machine,
hans
2016/02/12 01:42:33
I assume opening /dev/null doesn't work on Windows
hans
2016/02/12 01:42:33
That's pretty opaque. The current code will tell t
Mostyn Bramley-Moore
2016/02/15 13:29:44
Ahh, right- I copied this pattern from build/downl
| |
| 93 bytes_done = 0 | |
| 94 dots_printed = 0 | |
| 95 while True: | |
| 96 chunk = response.read(CHUNK_SIZE) | |
| 97 if not chunk: | |
| 98 break | |
| 99 output_file.write(chunk) | |
| 100 bytes_done += len(chunk) | |
| 101 num_dots = TOTAL_DOTS * bytes_done / total_size | |
| 102 sys.stdout.write('.' * (num_dots - dots_printed)) | |
| 103 sys.stdout.flush() | |
| 104 dots_printed = num_dots | |
| 105 if bytes_done != total_size: | |
| 106 raise urllib2.URLError("only got %d of %d bytes" % | |
| 107 (bytes_done, total_size)) | |
| 108 print ' Done.' | |
| 109 return | 95 return |
| 110 except urllib2.URLError as e: | 96 except Exception as e: |
| 111 sys.stdout.write('\n') | 97 sys.stdout.write('\n') |
| 112 print e | 98 print e |
| 113 if num_retries == 0 or isinstance(e, urllib2.HTTPError) and e.code == 404: | 99 if num_retries == 0: # TODO(mostynb): exit early on 404? |
| 114 raise e | 100 raise e |
| 115 num_retries -= 1 | 101 num_retries -= 1 |
| 116 print 'Retrying in %d s ...' % retry_wait_s | 102 print 'Retrying in %d s ...' % retry_wait_s |
| 117 time.sleep(retry_wait_s) | 103 time.sleep(retry_wait_s) |
| 118 retry_wait_s *= 2 | 104 retry_wait_s *= 2 |
| 119 | 105 |
| 120 | 106 |
| 121 def EnsureDirExists(path): | 107 def EnsureDirExists(path): |
| 122 if not os.path.exists(path): | 108 if not os.path.exists(path): |
| 123 print "Creating directory %s" % path | 109 print "Creating directory %s" % path |
| 124 os.makedirs(path) | 110 os.makedirs(path) |
| 125 | 111 |
| 126 | 112 |
| 127 def DownloadAndUnpack(url, output_dir): | 113 def DownloadAndUnpack(source, output_dir): |
| 128 with tempfile.TemporaryFile() as f: | 114 with tempfile.NamedTemporaryFile() as f: |
| 129 DownloadUrl(url, f) | 115 DownloadFile(source, f.name) |
| 130 f.seek(0) | 116 f.seek(0) |
| 131 EnsureDirExists(output_dir) | 117 EnsureDirExists(output_dir) |
| 132 if url.endswith('.zip'): | 118 if source.endswith('.zip'): |
| 133 zipfile.ZipFile(f).extractall(path=output_dir) | 119 zipfile.ZipFile(f).extractall(path=output_dir) |
| 134 else: | 120 else: |
| 135 tarfile.open(mode='r:gz', fileobj=f).extractall(path=output_dir) | 121 tarfile.open(mode='r:gz', fileobj=f).extractall(path=output_dir) |
| 136 | 122 |
| 137 | 123 |
| 138 def ReadStampFile(): | 124 def ReadStampFile(): |
| 139 """Return the contents of the stamp file, or '' if it doesn't exist.""" | 125 """Return the contents of the stamp file, or '' if it doesn't exist.""" |
| 140 try: | 126 try: |
| 141 with open(STAMP_FILE, 'r') as f: | 127 with open(STAMP_FILE, 'r') as f: |
| 142 return f.read().rstrip() | 128 return f.read().rstrip() |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 278 def DownloadHostGcc(args): | 264 def DownloadHostGcc(args): |
| 279 """Downloads gcc 4.8.2 and makes sure args.gcc_toolchain is set.""" | 265 """Downloads gcc 4.8.2 and makes sure args.gcc_toolchain is set.""" |
| 280 if not sys.platform.startswith('linux') or args.gcc_toolchain: | 266 if not sys.platform.startswith('linux') or args.gcc_toolchain: |
| 281 return | 267 return |
| 282 # Unconditionally download a prebuilt gcc to guarantee the included libstdc++ | 268 # Unconditionally download a prebuilt gcc to guarantee the included libstdc++ |
| 283 # works on Ubuntu Precise. | 269 # works on Ubuntu Precise. |
| 284 gcc_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, 'gcc482precise') | 270 gcc_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, 'gcc482precise') |
| 285 if not os.path.exists(gcc_dir): | 271 if not os.path.exists(gcc_dir): |
| 286 print 'Downloading pre-built GCC 4.8.2...' | 272 print 'Downloading pre-built GCC 4.8.2...' |
| 287 DownloadAndUnpack( | 273 DownloadAndUnpack( |
| 288 CDS_URL + '/tools/gcc482precise.tgz', LLVM_BUILD_TOOLS_DIR) | 274 CDS_BUCKET + '/tools/gcc482precise.tgz', LLVM_BUILD_TOOLS_DIR) |
| 289 args.gcc_toolchain = gcc_dir | 275 args.gcc_toolchain = gcc_dir |
| 290 | 276 |
| 291 | 277 |
| 292 def AddCMakeToPath(): | 278 def AddCMakeToPath(): |
| 293 """Download CMake and add it to PATH.""" | 279 """Download CMake and add it to PATH.""" |
| 294 if sys.platform == 'win32': | 280 if sys.platform == 'win32': |
| 295 zip_name = 'cmake-3.2.2-win32-x86.zip' | 281 zip_name = 'cmake-3.2.2-win32-x86.zip' |
| 296 cmake_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, | 282 cmake_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, |
| 297 'cmake-3.2.2-win32-x86', 'bin') | 283 'cmake-3.2.2-win32-x86', 'bin') |
| 298 else: | 284 else: |
| 299 suffix = 'Darwin' if sys.platform == 'darwin' else 'Linux' | 285 suffix = 'Darwin' if sys.platform == 'darwin' else 'Linux' |
| 300 zip_name = 'cmake322_%s.tgz' % suffix | 286 zip_name = 'cmake322_%s.tgz' % suffix |
| 301 cmake_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, 'cmake322', 'bin') | 287 cmake_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, 'cmake322', 'bin') |
| 302 if not os.path.exists(cmake_dir): | 288 if not os.path.exists(cmake_dir): |
| 303 DownloadAndUnpack(CDS_URL + '/tools/' + zip_name, LLVM_BUILD_TOOLS_DIR) | 289 DownloadAndUnpack(CDS_BUCKET + '/tools/' + zip_name, LLVM_BUILD_TOOLS_DIR) |
| 304 os.environ['PATH'] = cmake_dir + os.pathsep + os.environ.get('PATH', '') | 290 os.environ['PATH'] = cmake_dir + os.pathsep + os.environ.get('PATH', '') |
| 305 | 291 |
| 306 | 292 |
| 307 vs_version = None | 293 vs_version = None |
| 308 def GetVSVersion(): | 294 def GetVSVersion(): |
| 309 global vs_version | 295 global vs_version |
| 310 if vs_version: | 296 if vs_version: |
| 311 return vs_version | 297 return vs_version |
| 312 | 298 |
| 313 # Try using the toolchain in depot_tools. | 299 # Try using the toolchain in depot_tools. |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 337 if not need_gold_plugin or os.path.exists( | 323 if not need_gold_plugin or os.path.exists( |
| 338 os.path.join(LLVM_BUILD_DIR, "lib/LLVMgold.so")): | 324 os.path.join(LLVM_BUILD_DIR, "lib/LLVMgold.so")): |
| 339 return 0 | 325 return 0 |
| 340 | 326 |
| 341 # Reset the stamp file in case the build is unsuccessful. | 327 # Reset the stamp file in case the build is unsuccessful. |
| 342 WriteStampFile('') | 328 WriteStampFile('') |
| 343 | 329 |
| 344 if not args.force_local_build: | 330 if not args.force_local_build: |
| 345 cds_file = "clang-%s.tgz" % PACKAGE_VERSION | 331 cds_file = "clang-%s.tgz" % PACKAGE_VERSION |
| 346 if sys.platform == 'win32' or sys.platform == 'cygwin': | 332 if sys.platform == 'win32' or sys.platform == 'cygwin': |
| 347 cds_full_url = CDS_URL + '/Win/' + cds_file | 333 cds_source = CDS_BUCKET + '/Win/' + cds_file |
| 348 elif sys.platform == 'darwin': | 334 elif sys.platform == 'darwin': |
| 349 cds_full_url = CDS_URL + '/Mac/' + cds_file | 335 cds_source = CDS_BUCKET + '/Mac/' + cds_file |
| 350 else: | 336 else: |
| 351 assert sys.platform.startswith('linux') | 337 assert sys.platform.startswith('linux') |
| 352 cds_full_url = CDS_URL + '/Linux_x64/' + cds_file | 338 cds_source = CDS_BUCKET + '/Linux_x64/' + cds_file |
| 353 | 339 |
| 354 print 'Downloading prebuilt clang' | 340 print 'Downloading prebuilt clang' |
| 355 if os.path.exists(LLVM_BUILD_DIR): | 341 if os.path.exists(LLVM_BUILD_DIR): |
| 356 RmTree(LLVM_BUILD_DIR) | 342 RmTree(LLVM_BUILD_DIR) |
| 357 try: | 343 try: |
| 358 DownloadAndUnpack(cds_full_url, LLVM_BUILD_DIR) | 344 DownloadAndUnpack(cds_source, LLVM_BUILD_DIR) |
| 359 print 'clang %s unpacked' % PACKAGE_VERSION | 345 print 'clang %s unpacked' % PACKAGE_VERSION |
| 360 # Download the gold plugin if requested to by an environment variable. | 346 # Download the gold plugin if requested to by an environment variable. |
| 361 # This is used by the CFI ClusterFuzz bot, and it's required for official | 347 # This is used by the CFI ClusterFuzz bot, and it's required for official |
| 362 # builds on linux. | 348 # builds on linux. |
| 363 if need_gold_plugin: | 349 if need_gold_plugin: |
| 364 RunCommand(['python', CHROMIUM_DIR+'/build/download_gold_plugin.py']) | 350 RunCommand(['python', CHROMIUM_DIR+'/build/download_gold_plugin.py']) |
| 365 WriteStampFile(PACKAGE_VERSION) | 351 WriteStampFile(PACKAGE_VERSION) |
| 366 return 0 | 352 return 0 |
| 367 except urllib2.URLError: | 353 except Exception: |
|
hans
2016/02/12 01:42:33
This exception handler is much broader than the pr
| |
| 368 print 'Failed to download prebuilt clang %s' % cds_file | 354 print 'Failed to download prebuilt clang %s' % cds_file |
| 369 print 'Use --force-local-build if you want to build locally.' | 355 print 'Use --force-local-build if you want to build locally.' |
| 370 print 'Exiting.' | 356 print 'Exiting.' |
| 371 return 1 | 357 return 1 |
| 372 | 358 |
| 373 if args.with_android and not os.path.exists(ANDROID_NDK_DIR): | 359 if args.with_android and not os.path.exists(ANDROID_NDK_DIR): |
| 374 print 'Android NDK not found at ' + ANDROID_NDK_DIR | 360 print 'Android NDK not found at ' + ANDROID_NDK_DIR |
| 375 print 'The Android NDK is needed to build a Clang whose -fsanitize=address' | 361 print 'The Android NDK is needed to build a Clang whose -fsanitize=address' |
| 376 print 'works on Android. See ' | 362 print 'works on Android. See ' |
| 377 print 'https://www.chromium.org/developers/how-tos/android-build-instruction s' | 363 print 'https://www.chromium.org/developers/how-tos/android-build-instruction s' |
| (...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 763 args.force_local_build = True | 749 args.force_local_build = True |
| 764 if 'OS=android' not in os.environ.get('GYP_DEFINES', ''): | 750 if 'OS=android' not in os.environ.get('GYP_DEFINES', ''): |
| 765 # Only build the Android ASan rt on ToT bots when targetting Android. | 751 # Only build the Android ASan rt on ToT bots when targetting Android. |
| 766 args.with_android = False | 752 args.with_android = False |
| 767 | 753 |
| 768 return UpdateClang(args) | 754 return UpdateClang(args) |
| 769 | 755 |
| 770 | 756 |
| 771 if __name__ == '__main__': | 757 if __name__ == '__main__': |
| 772 sys.exit(main()) | 758 sys.exit(main()) |
| OLD | NEW |