Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / tools / clang / scripts / update.py
1 #!/usr/bin/env python
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
4 # found in the LICENSE file.
5
6 """Windows can't run .sh files, so this is a Python implementation of
7 update.sh. This script should replace update.sh on all platforms eventually."""
8
9 import os
10 import re
11 import shutil
12 import subprocess
13 import sys
14
15 # Do NOT CHANGE this if you don't know what you're doing -- see
16 # https://code.google.com/p/chromium/wiki/UpdatingClang
17 # Reverting problematic clang rolls is safe, though.
18 # Note: this revision is only used for Windows. Other platforms use update.sh.
19 LLVM_WIN_REVISION = 'HEAD'
20
21 # Path constants. (All of these should be absolute paths.)
22 THIS_DIR = os.path.abspath(os.path.dirname(__file__))
23 CHROMIUM_DIR = os.path.abspath(os.path.join(THIS_DIR, '..', '..', '..'))
24 LLVM_DIR = os.path.join(CHROMIUM_DIR, 'third_party', 'llvm')
25 LLVM_BUILD_DIR = os.path.join(CHROMIUM_DIR, 'third_party', 'llvm-build',
26                               'Release+Asserts')
27 COMPILER_RT_BUILD_DIR = os.path.join(LLVM_BUILD_DIR, '32bit-compiler-rt')
28 CLANG_DIR = os.path.join(LLVM_DIR, 'tools', 'clang')
29 COMPILER_RT_DIR = os.path.join(LLVM_DIR, 'projects', 'compiler-rt')
30 STAMP_FILE = os.path.join(LLVM_BUILD_DIR, 'cr_build_revision')
31
32 LLVM_REPO_URL='https://llvm.org/svn/llvm-project'
33 if 'LLVM_REPO_URL' in os.environ:
34   LLVM_REPO_URL = os.environ['LLVM_REPO_URL']
35
36
37 def ReadStampFile():
38   """Return the contents of the stamp file, or '' if it doesn't exist."""
39   try:
40     with open(STAMP_FILE, 'r') as f:
41       return f.read();
42   except IOError:
43     return ''
44
45
46 def WriteStampFile(s):
47   """Write s to the stamp file."""
48   if not os.path.exists(LLVM_BUILD_DIR):
49     os.makedirs(LLVM_BUILD_DIR)
50   with open(STAMP_FILE, 'w') as f:
51     f.write(s)
52
53
54 def DeleteFiles(dir, pattern):
55   """Delete all files in dir matching pattern."""
56   n = 0
57   regex = re.compile(r'^' + pattern + r'$')
58   for root, _, files in os.walk(dir):
59     for f in files:
60       if regex.match(f):
61         os.remove(os.path.join(root, f))
62         n += 1
63   return n
64
65
66 def ClobberChromiumBuildFiles():
67   """Clobber Chomium build files."""
68   print 'Clobbering Chromium build files...'
69   out_dir = os.path.join(CHROMIUM_DIR, 'out')
70   if os.path.isdir(out_dir):
71     shutil.rmtree(out_dir)
72     print 'Removed Chromium out dir: %s.' % (out_dir)
73
74
75 def RunCommand(command, tries=1):
76   """Run a command, possibly with multiple retries."""
77   for i in range(0, tries):
78     print 'Running %s (try #%d)' % (str(command), i + 1)
79     if subprocess.call(command, shell=True) == 0:
80       return
81     print 'Failed.'
82   sys.exit(1)
83
84
85 def Checkout(name, url, dir):
86   """Checkout the SVN module at url into dir. Use name for the log message."""
87   print "Checking out %s r%s into '%s'" % (name, LLVM_WIN_REVISION, dir)
88   RunCommand(['svn', 'checkout', '--force',
89               url + '@' + LLVM_WIN_REVISION, dir], tries=2)
90
91
92 vs_version = None
93 def GetVSVersion():
94   global vs_version
95   if not vs_version:
96     # TODO(hans): Find a less hacky way to find the MSVS installation.
97     sys.path.append(os.path.join(CHROMIUM_DIR, 'tools', 'gyp', 'pylib'))
98     import gyp.MSVSVersion
99     # We request VS 2013 because Clang won't build with 2010, and 2013 will be
100     # the default for Chromium soon anyway.
101     vs_version = gyp.MSVSVersion.SelectVisualStudioVersion('2013')
102   return vs_version
103
104
105 def UpdateClang():
106   print 'Updating Clang to %s...' % (LLVM_WIN_REVISION)
107   if LLVM_WIN_REVISION != 'HEAD' and ReadStampFile() == LLVM_WIN_REVISION:
108     print 'Already up to date.'
109     return 0
110
111   ClobberChromiumBuildFiles()
112
113   # Reset the stamp file in case the build is unsuccessful.
114   WriteStampFile('')
115
116   Checkout('LLVM', LLVM_REPO_URL + '/llvm/trunk', LLVM_DIR)
117   Checkout('Clang', LLVM_REPO_URL + '/cfe/trunk', CLANG_DIR)
118   Checkout('compiler-rt', LLVM_REPO_URL + '/compiler-rt/trunk', COMPILER_RT_DIR)
119
120   if not os.path.exists(LLVM_BUILD_DIR):
121     os.makedirs(LLVM_BUILD_DIR)
122   os.chdir(LLVM_BUILD_DIR)
123
124   if not re.search(r'cmake', os.environ['PATH'], flags=re.IGNORECASE):
125     # If CMake is not on the path, try looking in a standard location.
126     os.environ['PATH'] += os.pathsep + 'C:\\Program Files (x86)\\CMake 2.8\\bin'
127
128   RunCommand(GetVSVersion().SetupScript('x64') +
129              ['&&', 'cmake', '-GNinja', '-DCMAKE_BUILD_TYPE=Release',
130               '-DLLVM_ENABLE_ASSERTIONS=ON', LLVM_DIR])
131   RunCommand(GetVSVersion().SetupScript('x64') + ['&&', 'ninja', 'all'])
132
133   # Do an x86 build of compiler-rt to get the 32-bit ASan run-time.
134   # TODO(hans): Remove once the regular build above produces this.
135   if not os.path.exists(COMPILER_RT_BUILD_DIR):
136     os.makedirs(COMPILER_RT_BUILD_DIR)
137   os.chdir(COMPILER_RT_BUILD_DIR)
138   RunCommand(GetVSVersion().SetupScript('x86') +
139              ['&&', 'cmake', '-GNinja', '-DCMAKE_BUILD_TYPE=Release',
140               '-DLLVM_ENABLE_ASSERTIONS=ON', LLVM_DIR])
141   RunCommand(GetVSVersion().SetupScript('x86') + ['&&', 'ninja', 'compiler-rt'])
142
143   # TODO(hans): Make this (and the .gypi file) version number independent.
144   asan_rt_lib_src_dir = os.path.join(COMPILER_RT_BUILD_DIR, 'lib', 'clang',
145                                      '3.5.0', 'lib', 'windows')
146   asan_rt_lib_dst_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang',
147                                      '3.5.0', 'lib', 'windows')
148
149   if not os.path.exists(asan_rt_lib_dst_dir):
150     os.makedirs(asan_rt_lib_dst_dir)
151   for root, _, files in os.walk(asan_rt_lib_src_dir):
152     for f in files:
153       if re.match(r'^.*-i386\.lib$', f):
154         shutil.copy(os.path.join(root, f), asan_rt_lib_dst_dir)
155         print "Copying %s to %s" % (f, asan_rt_lib_dst_dir)
156
157   WriteStampFile(LLVM_WIN_REVISION)
158   print 'Clang update was successful.'
159   return 0
160
161
162 def main():
163   if not sys.platform in ['win32', 'cygwin']:
164     # For non-Windows, fall back to update.sh.
165     # TODO(hans): Make update.py replace update.sh completely.
166
167     # This script is called by gclient. gclient opens its hooks subprocesses
168     # with (stdout=subprocess.PIPE, stderr=subprocess.STDOUT) and then does
169     # custom output processing that breaks printing '\r' characters for
170     # single-line updating status messages as printed by curl and wget.
171     # Work around this by setting stderr of the update.sh process to stdin (!):
172     # gclient doesn't redirect stdin, and while stdin itself is read-only, a
173     # dup()ed sys.stdin is writable, try
174     #   fd2 = os.dup(sys.stdin.fileno()); os.write(fd2, 'hi')
175     # TODO: Fix gclient instead, http://crbug.com/95350
176     return subprocess.call(
177         [os.path.join(os.path.dirname(__file__), 'update.sh')] +  sys.argv[1:],
178         stderr=os.fdopen(os.dup(sys.stdin.fileno())))
179
180   if not re.search(r'\b(clang|asan)=1', os.environ.get('GYP_DEFINES', '')):
181     print 'Skipping Clang update (clang=1 was not set in GYP_DEFINES).'
182     return 0
183
184   if re.search(r'\b(make_clang_dir)=', os.environ.get('GYP_DEFINES', '')):
185     print 'Skipping Clang update (make_clang_dir= was set in GYP_DEFINES).'
186     return 0
187
188   return UpdateClang()
189
190
191 if __name__ == '__main__':
192   sys.exit(main())