Upstream version 11.40.277.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 # ASan on Windows is useful enough to use it even while the clang/win is still
22 # in bringup. Use a pinned revision to make it slightly more stable.
23 if (re.search(r'\b(asan)=1', os.environ.get('GYP_DEFINES', '')) and
24     not 'LLVM_FORCE_HEAD_REVISION' in os.environ):
25   LLVM_WIN_REVISION = '217738'
26
27 # Path constants. (All of these should be absolute paths.)
28 THIS_DIR = os.path.abspath(os.path.dirname(__file__))
29 CHROMIUM_DIR = os.path.abspath(os.path.join(THIS_DIR, '..', '..', '..'))
30 LLVM_DIR = os.path.join(CHROMIUM_DIR, 'third_party', 'llvm')
31 LLVM_BUILD_DIR = os.path.join(CHROMIUM_DIR, 'third_party', 'llvm-build',
32                               'Release+Asserts')
33 COMPILER_RT_BUILD_DIR = os.path.join(LLVM_BUILD_DIR, '32bit-compiler-rt')
34 CLANG_DIR = os.path.join(LLVM_DIR, 'tools', 'clang')
35 COMPILER_RT_DIR = os.path.join(LLVM_DIR, 'projects', 'compiler-rt')
36 STAMP_FILE = os.path.join(LLVM_BUILD_DIR, 'cr_build_revision')
37
38 LLVM_REPO_URL='https://llvm.org/svn/llvm-project'
39 if 'LLVM_REPO_URL' in os.environ:
40   LLVM_REPO_URL = os.environ['LLVM_REPO_URL']
41
42
43 def ReadStampFile():
44   """Return the contents of the stamp file, or '' if it doesn't exist."""
45   try:
46     with open(STAMP_FILE, 'r') as f:
47       return f.read();
48   except IOError:
49     return ''
50
51
52 def WriteStampFile(s):
53   """Write s to the stamp file."""
54   if not os.path.exists(LLVM_BUILD_DIR):
55     os.makedirs(LLVM_BUILD_DIR)
56   with open(STAMP_FILE, 'w') as f:
57     f.write(s)
58
59
60 def DeleteFiles(dir, pattern):
61   """Delete all files in dir matching pattern."""
62   n = 0
63   regex = re.compile(r'^' + pattern + r'$')
64   for root, _, files in os.walk(dir):
65     for f in files:
66       if regex.match(f):
67         os.remove(os.path.join(root, f))
68         n += 1
69   return n
70
71
72 def ClobberChromiumBuildFiles():
73   """Clobber Chomium build files."""
74   print 'Clobbering Chromium build files...'
75   out_dir = os.path.join(CHROMIUM_DIR, 'out')
76   if os.path.isdir(out_dir):
77     shutil.rmtree(out_dir)
78     print 'Removed Chromium out dir: %s.' % (out_dir)
79
80
81 def RunCommand(command, tries=1):
82   """Run a command, possibly with multiple retries."""
83   for i in range(0, tries):
84     print 'Running %s (try #%d)' % (str(command), i + 1)
85     if subprocess.call(command, shell=True) == 0:
86       return
87     print 'Failed.'
88   sys.exit(1)
89
90
91 def CopyFile(src, dst):
92   """Copy a file from src to dst."""
93   shutil.copy(src, dst)
94   print "Copying %s to %s" % (src, dst)
95
96
97 def CopyDirectoryContents(src, dst, filename_filter=None):
98   """Copy the files from directory src to dst
99   with an optional filename filter."""
100   if not os.path.exists(dst):
101     os.makedirs(dst)
102   for root, _, files in os.walk(src):
103     for f in files:
104       if filename_filter and not re.match(filename_filter, f):
105         continue
106       CopyFile(os.path.join(root, f), dst)
107
108
109 def Checkout(name, url, dir):
110   """Checkout the SVN module at url into dir. Use name for the log message."""
111   print "Checking out %s r%s into '%s'" % (name, LLVM_WIN_REVISION, dir)
112   RunCommand(['svn', 'checkout', '--force',
113               url + '@' + LLVM_WIN_REVISION, dir], tries=2)
114
115
116 def AddCMakeToPath():
117   """Look for CMake and add it to PATH if it's not there already."""
118   try:
119     # First check if cmake is already on PATH.
120     subprocess.call(['cmake', '--version'])
121     return
122   except OSError as e:
123     if e.errno != os.errno.ENOENT:
124       raise
125
126   cmake_locations = ['C:\\Program Files (x86)\\CMake\\bin',
127                      'C:\\Program Files (x86)\\CMake 2.8\\bin']
128   for d in cmake_locations:
129     if os.path.isdir(d):
130       os.environ['PATH'] = os.environ.get('PATH', '') + os.pathsep + d
131       return
132   print 'Failed to find CMake!'
133   sys.exit(1)
134
135
136 vs_version = None
137 def GetVSVersion():
138   global vs_version
139   if vs_version:
140     return vs_version
141
142   # Try using the toolchain in depot_tools.
143   # This sets environment variables used by SelectVisualStudioVersion below.
144   sys.path.append(os.path.join(CHROMIUM_DIR, 'build'))
145   import vs_toolchain
146   vs_toolchain.SetEnvironmentAndGetRuntimeDllDirs()
147
148   # Use gyp to find the MSVS installation, either in depot_tools as per above,
149   # or a system-wide installation otherwise.
150   sys.path.append(os.path.join(CHROMIUM_DIR, 'tools', 'gyp', 'pylib'))
151   import gyp.MSVSVersion
152   vs_version = gyp.MSVSVersion.SelectVisualStudioVersion('2013')
153   return vs_version
154
155
156 def SubversionCmakeArg():
157   # Since cmake's find_program can only find .exe and .com,
158   # svn.bat in depot_tools will be ignored.
159   default_pathext = ('.com', '.exe', '.bat', '.cmd')
160   for path in os.environ.get('PATH', '').split(os.pathsep):
161     for ext in default_pathext:
162       candidate = os.path.join(path, 'svn' + ext)
163       if os.path.isfile(candidate):
164         return '-DSubversion_SVN_EXECUTABLE=%s' % candidate
165   return ''
166
167
168 def UpdateClang():
169   print 'Updating Clang to %s...' % (LLVM_WIN_REVISION)
170   if LLVM_WIN_REVISION != 'HEAD' and ReadStampFile() == LLVM_WIN_REVISION:
171     print 'Already up to date.'
172     return 0
173
174   AddCMakeToPath()
175   ClobberChromiumBuildFiles()
176
177   # Reset the stamp file in case the build is unsuccessful.
178   WriteStampFile('')
179
180   Checkout('LLVM', LLVM_REPO_URL + '/llvm/trunk', LLVM_DIR)
181   Checkout('Clang', LLVM_REPO_URL + '/cfe/trunk', CLANG_DIR)
182   Checkout('compiler-rt', LLVM_REPO_URL + '/compiler-rt/trunk', COMPILER_RT_DIR)
183
184   if not os.path.exists(LLVM_BUILD_DIR):
185     os.makedirs(LLVM_BUILD_DIR)
186   os.chdir(LLVM_BUILD_DIR)
187
188   RunCommand(GetVSVersion().SetupScript('x64') +
189              ['&&', 'cmake', '-GNinja', '-DCMAKE_BUILD_TYPE=Release',
190               '-DLLVM_ENABLE_ASSERTIONS=ON', SubversionCmakeArg(), LLVM_DIR])
191   RunCommand(GetVSVersion().SetupScript('x64') + ['&&', 'ninja', 'all'])
192
193   # Do an x86 build of compiler-rt to get the 32-bit ASan run-time.
194   # TODO(hans): Remove once the regular build above produces this.
195   if not os.path.exists(COMPILER_RT_BUILD_DIR):
196     os.makedirs(COMPILER_RT_BUILD_DIR)
197   os.chdir(COMPILER_RT_BUILD_DIR)
198   RunCommand(GetVSVersion().SetupScript('x86') +
199              ['&&', 'cmake', '-GNinja', '-DCMAKE_BUILD_TYPE=Release',
200               '-DLLVM_ENABLE_ASSERTIONS=ON', LLVM_DIR])
201   RunCommand(GetVSVersion().SetupScript('x86') + ['&&', 'ninja', 'compiler-rt'])
202
203   asan_rt_bin_src_dir = os.path.join(COMPILER_RT_BUILD_DIR, 'bin')
204   asan_rt_bin_dst_dir = os.path.join(LLVM_BUILD_DIR, 'bin')
205   CopyDirectoryContents(asan_rt_bin_src_dir, asan_rt_bin_dst_dir,
206                         r'^.*-i386\.dll$')
207
208   # TODO(hans): Make this (and the .gypi file) version number independent.
209   asan_rt_lib_src_dir = os.path.join(COMPILER_RT_BUILD_DIR, 'lib', 'clang',
210                                      '3.6.0', 'lib', 'windows')
211   asan_rt_lib_dst_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang',
212                                      '3.6.0', 'lib', 'windows')
213   CopyDirectoryContents(asan_rt_lib_src_dir, asan_rt_lib_dst_dir,
214                         r'^.*-i386\.lib$')
215
216   CopyFile(os.path.join(asan_rt_lib_src_dir, '..', '..', 'asan_blacklist.txt'),
217            os.path.join(asan_rt_lib_dst_dir, '..', '..'))
218
219   # Make an extra copy of the sanitizer headers, to be put on the include path
220   # of the fallback compiler.
221   sanitizer_include_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang', '3.6.0',
222                                        'include', 'sanitizer')
223   aux_sanitizer_include_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang',
224                                            '3.6.0', 'include_sanitizer',
225                                            'sanitizer')
226   if not os.path.exists(aux_sanitizer_include_dir):
227     os.makedirs(aux_sanitizer_include_dir)
228   for _, _, files in os.walk(sanitizer_include_dir):
229     for f in files:
230       CopyFile(os.path.join(sanitizer_include_dir, f),
231                aux_sanitizer_include_dir)
232
233   WriteStampFile(LLVM_WIN_REVISION)
234   print 'Clang update was successful.'
235   return 0
236
237
238 def main():
239   if not sys.platform in ['win32', 'cygwin']:
240     # For non-Windows, fall back to update.sh.
241     # TODO(hans): Make update.py replace update.sh completely.
242
243     # This script is called by gclient. gclient opens its hooks subprocesses
244     # with (stdout=subprocess.PIPE, stderr=subprocess.STDOUT) and then does
245     # custom output processing that breaks printing '\r' characters for
246     # single-line updating status messages as printed by curl and wget.
247     # Work around this by setting stderr of the update.sh process to stdin (!):
248     # gclient doesn't redirect stdin, and while stdin itself is read-only, a
249     # dup()ed sys.stdin is writable, try
250     #   fd2 = os.dup(sys.stdin.fileno()); os.write(fd2, 'hi')
251     # TODO: Fix gclient instead, http://crbug.com/95350
252     return subprocess.call(
253         [os.path.join(os.path.dirname(__file__), 'update.sh')] +  sys.argv[1:],
254         stderr=os.fdopen(os.dup(sys.stdin.fileno())))
255
256   if not re.search(r'\b(clang|asan)=1', os.environ.get('GYP_DEFINES', '')):
257     print 'Skipping Clang update (clang=1 was not set in GYP_DEFINES).'
258     return 0
259
260   if re.search(r'\b(make_clang_dir)=', os.environ.get('GYP_DEFINES', '')):
261     print 'Skipping Clang update (make_clang_dir= was set in GYP_DEFINES).'
262     return 0
263
264   return UpdateClang()
265
266
267 if __name__ == '__main__':
268   sys.exit(main())