Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / tools / clang / scripts / update.py
index bdc781f..d23eb41 100755 (executable)
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""Windows can't run .sh files, so this is a small python wrapper around
-update.sh.
-"""
+"""Windows can't run .sh files, so this is a Python implementation of
+update.sh. This script should replace update.sh on all platforms eventually."""
 
 import os
+import re
 import subprocess
 import sys
 
+# Do NOT CHANGE this if you don't know what you're doing -- see
+# https://code.google.com/p/chromium/wiki/UpdatingClang
+# Reverting problematic clang rolls is safe, though.
+# Note: this revision is only used for Windows. Other platforms use update.sh.
+LLVM_WINDOWS_REVISION = '201604'
+
+# Path constants. (All of these should be absolute paths.)
+THIS_DIR = os.path.abspath(os.path.dirname(__file__))
+CHROMIUM_DIR = os.path.abspath(os.path.join(THIS_DIR, '..', '..', '..'))
+LLVM_DIR = os.path.join(CHROMIUM_DIR, 'third_party', 'llvm')
+LLVM_BUILD_DIR = os.path.join(CHROMIUM_DIR, 'third_party', 'llvm-build',
+                              'Release+Asserts')
+CLANG_DIR = os.path.join(LLVM_DIR, 'tools', 'clang')
+COMPILER_RT_DIR = os.path.join(LLVM_DIR, 'projects', 'compiler-rt')
+STAMP_FILE = os.path.join(LLVM_BUILD_DIR, 'cr_build_revision')
+
+LLVM_REPO_URL='https://llvm.org/svn/llvm-project'
+if 'LLVM_REPO_URL' in os.environ:
+  LLVM_REPO_URL = os.environ['LLVM_REPO_URL']
+
+
+def ReadStampFile():
+  """Return the contents of the stamp file, or '' if it doesn't exist."""
+  try:
+    with open(STAMP_FILE, 'r') as f:
+      return f.read();
+  except IOError:
+    return ''
+
+
+def WriteStampFile(s):
+  """Write s to the stamp file."""
+  if not os.path.exists(LLVM_BUILD_DIR):
+    os.makedirs(LLVM_BUILD_DIR)
+  with open(STAMP_FILE, 'w') as f:
+    f.write(s)
+
+
+def DeleteFiles(dir, pattern):
+  """Delete all files in dir matching pattern."""
+  n = 0
+  regex = re.compile(r'^' + pattern + r'$')
+  for root, _, files in os.walk(dir):
+    for f in files:
+      if regex.match(f):
+        os.remove(os.path.join(root, f))
+        n += 1
+  return n
+
+
+def ClobberChromiumBuildFiles():
+  """Clobber Chomium build files."""
+  print 'Clobbering Chromium build files...'
+  n = 0
+  dirs = [
+    os.path.join(CHROMIUM_DIR, 'out/Debug'),
+    os.path.join(CHROMIUM_DIR, 'out/Release'),
+  ]
+  for d in dirs:
+    if not os.path.exists(d):
+      continue
+    n += DeleteFiles(d, r'.*\.o')
+    n += DeleteFiles(d, r'.*\.obj')
+    n += DeleteFiles(d, r'stamp.untar')
+  print 'Removed %d files.' % (n)
+
+
+def RunCommand(command, tries=1):
+  """Run a command, possibly with multiple retries."""
+  for i in range(0, tries):
+    print 'Running %s (try #%d)' % (str(command), i + 1)
+    if subprocess.call(command, shell=True) == 0:
+      return
+    print 'Failed.'
+  sys.exit(1)
+
+
+def Checkout(name, url, dir):
+  """Checkout the SVN module at url into dir. Use name for the log message."""
+  print "Checking out %s r%s into '%s'" % (name, LLVM_WINDOWS_REVISION, dir)
+  RunCommand(['svn', 'checkout', '--force',
+              url + '@' + LLVM_WINDOWS_REVISION, dir], tries=2)
+
+
+vs_version = None
+def GetVSVersion():
+  global vs_version
+  if not vs_version:
+    # TODO(hans): Find a less hacky way to find the MSVS installation.
+    sys.path.append(os.path.join(CHROMIUM_DIR, 'tools', 'gyp', 'pylib'))
+    import gyp.MSVSVersion
+    # We request VS 2013 because Clang won't build with 2010, and 2013 will be
+    # the default for Chromium soon anyway.
+    vs_version = gyp.MSVSVersion.SelectVisualStudioVersion('2013')
+  return vs_version
+
+
+def UpdateClang():
+  print 'Updating Clang to %s...' % (LLVM_WINDOWS_REVISION)
+  if ReadStampFile() == LLVM_WINDOWS_REVISION:
+    print 'Already up to date.'
+    return 0
+
+  ClobberChromiumBuildFiles()
+
+  # Reset the stamp file in case the build is unsuccessful.
+  WriteStampFile('')
+
+  Checkout('LLVM', LLVM_REPO_URL + '/llvm/trunk', LLVM_DIR)
+  Checkout('Clang', LLVM_REPO_URL + '/cfe/trunk', CLANG_DIR)
+  Checkout('compiler-rt', LLVM_REPO_URL + '/compiler-rt/trunk', COMPILER_RT_DIR)
+
+  if not os.path.exists(LLVM_BUILD_DIR):
+    os.makedirs(LLVM_BUILD_DIR)
+  os.chdir(LLVM_BUILD_DIR)
+
+  if not re.search(r'cmake', os.environ['PATH'], flags=re.IGNORECASE):
+    # If CMake is not on the path, try looking in a standard location.
+    os.environ['PATH'] += os.pathsep + 'C:\\Program Files (x86)\\CMake 2.8\\bin'
+
+  RunCommand(GetVSVersion().SetupScript('x64') +
+             ['&&', 'cmake', '-GNinja', '-DCMAKE_BUILD_TYPE=Release',
+              '-DLLVM_ENABLE_ASSERTIONS=ON', LLVM_DIR])
+
+  RunCommand(GetVSVersion().SetupScript('x64') + ['&&', 'ninja', 'all'])
+
+  WriteStampFile(LLVM_WINDOWS_REVISION)
+  print 'Clang update was successful.'
+  return 0
+
 
 def main():
-  if sys.platform in ['win32', 'cygwin']:
+  if not sys.platform in ['win32', 'cygwin']:
+    # For non-Windows, fall back to update.sh.
+    # TODO(hans): Make update.py replace update.sh completely.
+
+    # This script is called by gclient. gclient opens its hooks subprocesses
+    # with (stdout=subprocess.PIPE, stderr=subprocess.STDOUT) and then does
+    # custom output processing that breaks printing '\r' characters for
+    # single-line updating status messages as printed by curl and wget.
+    # Work around this by setting stderr of the update.sh process to stdin (!):
+    # gclient doesn't redirect stdin, and while stdin itself is read-only, a
+    # dup()ed sys.stdin is writable, try
+    #   fd2 = os.dup(sys.stdin.fileno()); os.write(fd2, 'hi')
+    # TODO: Fix gclient instead, http://crbug.com/95350
+    return subprocess.call(
+        [os.path.join(os.path.dirname(__file__), 'update.sh')] +  sys.argv[1:],
+        stderr=os.fdopen(os.dup(sys.stdin.fileno())))
+
+  if not re.search('clang=1', os.environ.get('GYP_DEFINES', '')):
+    print 'Skipping Clang update (clang=1 was not set in GYP_DEFINES).'
     return 0
 
-  # This script is called by gclient. gclient opens its hooks subprocesses with
-  # (stdout=subprocess.PIPE, stderr=subprocess.STDOUT) and then does custom
-  # output processing that breaks printing '\r' characters for single-line
-  # updating status messages as printed by curl and wget.
-  # Work around this by setting stderr of the update.sh process to stdin (!):
-  # gclient doesn't redirect stdin, and while stdin itself is read-only, a
-  # dup()ed sys.stdin is writable, try
-  #   fd2 = os.dup(sys.stdin.fileno()); os.write(fd2, 'hi')
-  # TODO: Fix gclient instead, http://crbug.com/95350
-  return subprocess.call(
-      [os.path.join(os.path.dirname(__file__), 'update.sh')] +  sys.argv[1:],
-      stderr=os.fdopen(os.dup(sys.stdin.fileno())))
+  return UpdateClang()
 
 
 if __name__ == '__main__':