| Index: tools/clang/scripts/package.py
 | 
| diff --git a/tools/clang/scripts/package.py b/tools/clang/scripts/package.py
 | 
| new file mode 100755
 | 
| index 0000000000000000000000000000000000000000..be8498f527e123da01ccffcf952ea5472d8e1a9e
 | 
| --- /dev/null
 | 
| +++ b/tools/clang/scripts/package.py
 | 
| @@ -0,0 +1,245 @@
 | 
| +#!/usr/bin/env python
 | 
| +# Copyright (c) 2015 The Chromium Authors. All rights reserved.
 | 
| +# Use of this source code is governed by a BSD-style license that can be
 | 
| +# found in the LICENSE file.
 | 
| +
 | 
| +"""This script will check out llvm and clang, and then package the results up
 | 
| +to a tgz file."""
 | 
| +
 | 
| +import argparse
 | 
| +import fnmatch
 | 
| +import itertools
 | 
| +import os
 | 
| +import shutil
 | 
| +import subprocess
 | 
| +import sys
 | 
| +import tarfile
 | 
| +
 | 
| +# Path constants.
 | 
| +THIS_DIR = os.path.dirname(__file__)
 | 
| +THIRD_PARTY_DIR = os.path.join(THIS_DIR, '..', '..', '..', 'third_party')
 | 
| +LLVM_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm')
 | 
| +LLVM_BOOTSTRAP_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm-bootstrap')
 | 
| +LLVM_BOOTSTRAP_INSTALL_DIR = os.path.join(THIRD_PARTY_DIR,
 | 
| +                                          'llvm-bootstrap-install')
 | 
| +LLVM_BUILD_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm-build')
 | 
| +LLVM_RELEASE_DIR = os.path.join(LLVM_BUILD_DIR, 'Release+Asserts')
 | 
| +STAMP_FILE = os.path.join(LLVM_BUILD_DIR, 'cr_build_revision')
 | 
| +
 | 
| +
 | 
| +def Tee(output, logfile):
 | 
| +  logfile.write(output)
 | 
| +  print output,
 | 
| +
 | 
| +
 | 
| +def TeeCmd(cmd, logfile, fail_hard=True):
 | 
| +  """Runs cmd and writes the output to both stdout and logfile."""
 | 
| +  # Reading from PIPE can deadlock if one buffer is full but we wait on a
 | 
| +  # different one.  To work around this, pipe the subprocess's stderr to
 | 
| +  # its stdout buffer and don't give it a stdin.
 | 
| +  # shell=True is required in cmd.exe since depot_tools has an svn.bat, and
 | 
| +  # bat files only work with shell=True set.
 | 
| +  proc = subprocess.Popen(cmd, bufsize=1, shell=sys.platform == 'win32',
 | 
| +                          stdin=open(os.devnull), stdout=subprocess.PIPE,
 | 
| +                          stderr=subprocess.STDOUT)
 | 
| +  for line in iter(proc.stdout.readline,''):
 | 
| +    Tee(line, logfile)
 | 
| +    if proc.poll() is not None:
 | 
| +      break
 | 
| +  exit_code = proc.wait()
 | 
| +  if exit_code != 0 and fail_hard:
 | 
| +    print 'Failed:', cmd
 | 
| +    sys.exit(1)
 | 
| +
 | 
| +
 | 
| +def PrintTarProgress(tarinfo):
 | 
| +  print 'Adding', tarinfo.name
 | 
| +  return tarinfo
 | 
| +
 | 
| +
 | 
| +def main():
 | 
| +  if sys.platform == 'win32':
 | 
| +    try:
 | 
| +      subprocess.check_output(['grep', '--help'], shell=True)
 | 
| +    except subprocess.CalledProcessError:
 | 
| +      print 'Add gnuwin32 to your PATH, then try again.'
 | 
| +      return 1
 | 
| +
 | 
| +  parser = argparse.ArgumentParser(description='build and package clang')
 | 
| +  parser.add_argument('--gcc-toolchain',
 | 
| +                      help="the prefix for the GCC version used for building. "
 | 
| +                           "For /opt/foo/bin/gcc, pass "
 | 
| +                           "'--gcc-toolchain '/opt/foo'")
 | 
| +
 | 
| +  args = parser.parse_args()
 | 
| +
 | 
| +  with open('buildlog.txt', 'w') as log:
 | 
| +    Tee('Diff in llvm:\n', log)
 | 
| +    TeeCmd(['svn', 'stat', LLVM_DIR], log, fail_hard=False)
 | 
| +    TeeCmd(['svn', 'diff', LLVM_DIR], log, fail_hard=False)
 | 
| +    Tee('Diff in llvm/tools/clang:\n', log)
 | 
| +    TeeCmd(['svn', 'stat', os.path.join(LLVM_DIR, 'tools', 'clang')],
 | 
| +           log, fail_hard=False)
 | 
| +    TeeCmd(['svn', 'diff', os.path.join(LLVM_DIR, 'tools', 'clang')],
 | 
| +           log, fail_hard=False)
 | 
| +    # TODO(thakis): compiler-rt is in projects/compiler-rt on Windows but
 | 
| +    # llvm/compiler-rt elsewhere. So this diff call is currently only right on
 | 
| +    # Windows.
 | 
| +    Tee('Diff in llvm/compiler-rt:\n', log)
 | 
| +    TeeCmd(['svn', 'stat', os.path.join(LLVM_DIR, 'projects', 'compiler-rt')],
 | 
| +           log, fail_hard=False)
 | 
| +    TeeCmd(['svn', 'diff', os.path.join(LLVM_DIR, 'projects', 'compiler-rt')],
 | 
| +           log, fail_hard=False)
 | 
| +    Tee('Diff in llvm/projects/libcxx:\n', log)
 | 
| +    TeeCmd(['svn', 'stat', os.path.join(LLVM_DIR, 'projects', 'libcxx')],
 | 
| +           log, fail_hard=False)
 | 
| +    TeeCmd(['svn', 'diff', os.path.join(LLVM_DIR, 'projects', 'libcxx')],
 | 
| +           log, fail_hard=False)
 | 
| +    Tee('Diff in llvm/projects/libcxxabi:\n', log)
 | 
| +    TeeCmd(['svn', 'stat', os.path.join(LLVM_DIR, 'projects', 'libcxxabi')],
 | 
| +           log, fail_hard=False)
 | 
| +    TeeCmd(['svn', 'diff', os.path.join(LLVM_DIR, 'projects', 'libcxxabi')],
 | 
| +           log, fail_hard=False)
 | 
| +
 | 
| +    Tee('Starting build\n', log)
 | 
| +
 | 
| +    # Do a clobber build.
 | 
| +    shutil.rmtree(LLVM_BOOTSTRAP_DIR, ignore_errors=True)
 | 
| +    shutil.rmtree(LLVM_BOOTSTRAP_INSTALL_DIR, ignore_errors=True)
 | 
| +    shutil.rmtree(LLVM_BUILD_DIR, ignore_errors=True)
 | 
| +
 | 
| +    build_cmd = [sys.executable, os.path.join(THIS_DIR, 'update.py'),
 | 
| +                 '--bootstrap', '--force-local-build', '--run-tests',
 | 
| +                 '--no-stdin-hack']
 | 
| +    if args.gcc_toolchain is not None:
 | 
| +      build_cmd.extend(['--gcc-toolchain', args.gcc_toolchain])
 | 
| +    TeeCmd(build_cmd, log)
 | 
| +
 | 
| +  stamp = open(STAMP_FILE).read().rstrip()
 | 
| +  pdir = 'clang-' + stamp
 | 
| +  print pdir
 | 
| +  shutil.rmtree(pdir, ignore_errors=True)
 | 
| +
 | 
| +  # Copy a whitelist of files to the directory we're going to tar up.
 | 
| +  # This supports the same patterns that the fnmatch module understands.
 | 
| +  exe_ext = '.exe' if sys.platform == 'win32' else ''
 | 
| +  want = ['bin/llvm-symbolizer' + exe_ext,
 | 
| +          'lib/clang/*/asan_blacklist.txt',
 | 
| +          'lib/clang/*/cfi_blacklist.txt',
 | 
| +          # Copy built-in headers (lib/clang/3.x.y/include).
 | 
| +          'lib/clang/*/include/*',
 | 
| +          ]
 | 
| +  if sys.platform == 'win32':
 | 
| +    want.append('bin/clang-cl.exe')
 | 
| +    want.append('bin/lld-link.exe')
 | 
| +  else:
 | 
| +    so_ext = 'dylib' if sys.platform == 'darwin' else 'so'
 | 
| +    want.extend(['bin/clang',
 | 
| +                 'lib/libFindBadConstructs.' + so_ext,
 | 
| +                 'lib/libBlinkGCPlugin.' + so_ext,
 | 
| +                 ])
 | 
| +  if sys.platform == 'darwin':
 | 
| +    want.extend(['bin/libc++.1.dylib',
 | 
| +                 # Copy only the OSX (ASan and profile) and iossim (ASan)
 | 
| +                 # runtime libraries:
 | 
| +                 'lib/clang/*/lib/darwin/*asan_osx*',
 | 
| +                 'lib/clang/*/lib/darwin/*asan_iossim*',
 | 
| +                 'lib/clang/*/lib/darwin/*profile_osx*',
 | 
| +                 ])
 | 
| +  elif sys.platform.startswith('linux'):
 | 
| +    # Copy only
 | 
| +    # lib/clang/*/lib/linux/libclang_rt.{[atm]san,san,ubsan,profile}-*.a ,
 | 
| +    # but not dfsan.
 | 
| +    want.extend(['lib/clang/*/lib/linux/*[atm]san*',
 | 
| +                 'lib/clang/*/lib/linux/*ubsan*',
 | 
| +                 'lib/clang/*/lib/linux/*libclang_rt.san*',
 | 
| +                 'lib/clang/*/lib/linux/*profile*',
 | 
| +                 'lib/clang/*/msan_blacklist.txt',
 | 
| +                 ])
 | 
| +  elif sys.platform == 'win32':
 | 
| +    want.extend(['lib/clang/*/lib/windows/clang_rt.asan*.dll',
 | 
| +                 'lib/clang/*/lib/windows/clang_rt.asan*.lib',
 | 
| +                 'lib/clang/*/include_sanitizer/*',
 | 
| +                 ])
 | 
| +  if args.gcc_toolchain is not None:
 | 
| +    # Copy the stdlibc++.so.6 we linked Clang against so it can run.
 | 
| +    want.append('lib/libstdc++.so.6')
 | 
| +
 | 
| +  for root, dirs, files in os.walk(LLVM_RELEASE_DIR):
 | 
| +    # root: third_party/llvm-build/Release+Asserts/lib/..., rel_root: lib/...
 | 
| +    rel_root = root[len(LLVM_RELEASE_DIR)+1:]
 | 
| +    rel_files = [os.path.join(rel_root, f) for f in files]
 | 
| +    wanted_files = list(set(itertools.chain.from_iterable(
 | 
| +        fnmatch.filter(rel_files, p) for p in want)))
 | 
| +    if wanted_files:
 | 
| +      # Guaranteed to not yet exist at this point:
 | 
| +      os.makedirs(os.path.join(pdir, rel_root))
 | 
| +    for f in wanted_files:
 | 
| +      src = os.path.join(LLVM_RELEASE_DIR, f)
 | 
| +      dest = os.path.join(pdir, f)
 | 
| +      shutil.copy(src, dest)
 | 
| +      # Strip libraries.
 | 
| +      if sys.platform == 'darwin' and f.endswith('.dylib'):
 | 
| +        # Fix LC_ID_DYLIB for the ASan dynamic libraries to be relative to
 | 
| +        # @executable_path.
 | 
| +        # TODO(glider): this is transitional. We'll need to fix the dylib
 | 
| +        # name either in our build system, or in Clang. See also
 | 
| +        # http://crbug.com/344836.
 | 
| +        subprocess.call(['install_name_tool', '-id',
 | 
| +                         '@executable_path/' + os.path.basename(dest), dest])
 | 
| +        subprocess.call(['strip', '-x', dest])
 | 
| +      elif (sys.platform.startswith('linux') and
 | 
| +            os.path.splitext(f)[1] in ['.so', '.a']):
 | 
| +        subprocess.call(['strip', '-g', dest])
 | 
| +
 | 
| +  # Set up symlinks.
 | 
| +  if sys.platform != 'win32':
 | 
| +    os.symlink('clang', os.path.join(pdir, 'bin', 'clang++'))
 | 
| +    os.symlink('clang', os.path.join(pdir, 'bin', 'clang-cl'))
 | 
| +  if sys.platform == 'darwin':
 | 
| +    os.symlink('libc++.1.dylib', os.path.join(pdir, 'bin', 'libc++.dylib'))
 | 
| +    # Also copy libc++ headers.
 | 
| +    shutil.copytree(os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'include', 'c++'),
 | 
| +                    os.path.join(pdir, 'include', 'c++'))
 | 
| +
 | 
| +  # Copy buildlog over.
 | 
| +  shutil.copy('buildlog.txt', pdir)
 | 
| +
 | 
| +  # Create archive.
 | 
| +  tar_entries = ['bin', 'lib', 'buildlog.txt']
 | 
| +  if sys.platform == 'darwin':
 | 
| +    tar_entries += ['include']
 | 
| +  with tarfile.open(pdir + '.tgz', 'w:gz') as tar:
 | 
| +    for entry in tar_entries:
 | 
| +      tar.add(os.path.join(pdir, entry), arcname=entry, filter=PrintTarProgress)
 | 
| +
 | 
| +  if sys.platform == 'darwin':
 | 
| +    platform = 'Mac'
 | 
| +  elif sys.platform == 'win32':
 | 
| +    platform = 'Win'
 | 
| +  else:
 | 
| +    platform = 'Linux_x64'
 | 
| +
 | 
| +  print 'To upload, run:'
 | 
| +  print ('gsutil cp -a public-read %s.tgz '
 | 
| +         'gs://chromium-browser-clang/%s/%s.tgz') % (pdir, platform, pdir)
 | 
| +
 | 
| +  # Zip up gold plugin on Linux.
 | 
| +  if sys.platform.startswith('linux'):
 | 
| +    golddir = 'llvmgold-' + stamp
 | 
| +    shutil.rmtree(golddir, ignore_errors=True)
 | 
| +    os.makedirs(os.path.join(golddir, 'lib'))
 | 
| +    shutil.copy(os.path.join(LLVM_RELEASE_DIR, 'lib', 'LLVMgold.so'),
 | 
| +                os.path.join(golddir, 'lib'))
 | 
| +    with tarfile.open(golddir + '.tgz', 'w:gz') as tar:
 | 
| +      tar.add(os.path.join(golddir, 'lib'), arcname='lib',
 | 
| +              filter=PrintTarProgress)
 | 
| +    print ('gsutil cp -a public-read %s.tgz '
 | 
| +           'gs://chromium-browser-clang/%s/%s.tgz') % (golddir, platform,
 | 
| +                                                       golddir)
 | 
| +
 | 
| +  # FIXME: Warn if the file already exists on the server.
 | 
| +
 | 
| +
 | 
| +if __name__ == '__main__':
 | 
| +  sys.exit(main())
 | 
| 
 |