blob: 851ea321cdcd763a1a64821b9676a38c80c7882b [file] [log] [blame]
Ben Murdochf91f0612016-11-29 16:50:11 +00001#!/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"""This script is used to download prebuilt clang binaries.
7
8It is also used by package.py to build the prebuilt clang binaries."""
9
10import argparse
11import distutils.spawn
12import glob
13import os
14import pipes
15import re
16import shutil
17import subprocess
18import stat
19import sys
20import tarfile
21import tempfile
22import time
23import urllib2
24import zipfile
25
26
27# Do NOT CHANGE this if you don't know what you're doing -- see
28# https://chromium.googlesource.com/chromium/src/+/master/docs/updating_clang.md
29# Reverting problematic clang rolls is safe, though.
Rubin Xu2894c6a2019-02-07 16:01:35 +000030CLANG_REVISION = '338452'
Ben Murdochf91f0612016-11-29 16:50:11 +000031
Rubin Xu2894c6a2019-02-07 16:01:35 +000032use_head_revision = bool(os.environ.get('LLVM_FORCE_HEAD_REVISION', '0')
33 in ('1', 'YES'))
Ben Murdochf91f0612016-11-29 16:50:11 +000034if use_head_revision:
35 CLANG_REVISION = 'HEAD'
36
37# This is incremented when pushing a new build of Clang at the same revision.
Rubin Xu2894c6a2019-02-07 16:01:35 +000038CLANG_SUB_REVISION=1
Ben Murdochf91f0612016-11-29 16:50:11 +000039
40PACKAGE_VERSION = "%s-%s" % (CLANG_REVISION, CLANG_SUB_REVISION)
41
42# Path constants. (All of these should be absolute paths.)
43THIS_DIR = os.path.abspath(os.path.dirname(__file__))
44CHROMIUM_DIR = os.path.abspath(os.path.join(THIS_DIR, '..', '..', '..'))
Rubin Xu2894c6a2019-02-07 16:01:35 +000045GCLIENT_CONFIG = os.path.join(os.path.dirname(CHROMIUM_DIR), '.gclient')
Ben Murdochf91f0612016-11-29 16:50:11 +000046THIRD_PARTY_DIR = os.path.join(CHROMIUM_DIR, 'third_party')
47LLVM_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm')
48LLVM_BOOTSTRAP_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm-bootstrap')
49LLVM_BOOTSTRAP_INSTALL_DIR = os.path.join(THIRD_PARTY_DIR,
50 'llvm-bootstrap-install')
Ben Murdochf91f0612016-11-29 16:50:11 +000051CHROME_TOOLS_SHIM_DIR = os.path.join(LLVM_DIR, 'tools', 'chrometools')
52LLVM_BUILD_DIR = os.path.join(CHROMIUM_DIR, 'third_party', 'llvm-build',
53 'Release+Asserts')
Rubin Xu2894c6a2019-02-07 16:01:35 +000054THREADS_ENABLED_BUILD_DIR = os.path.join(LLVM_BUILD_DIR, 'threads_enabled')
Ben Murdochf91f0612016-11-29 16:50:11 +000055COMPILER_RT_BUILD_DIR = os.path.join(LLVM_BUILD_DIR, 'compiler-rt')
56CLANG_DIR = os.path.join(LLVM_DIR, 'tools', 'clang')
57LLD_DIR = os.path.join(LLVM_DIR, 'tools', 'lld')
58# compiler-rt is built as part of the regular LLVM build on Windows to get
59# the 64-bit runtime, and out-of-tree elsewhere.
60# TODO(thakis): Try to unify this.
61if sys.platform == 'win32':
62 COMPILER_RT_DIR = os.path.join(LLVM_DIR, 'projects', 'compiler-rt')
63else:
64 COMPILER_RT_DIR = os.path.join(LLVM_DIR, 'compiler-rt')
65LIBCXX_DIR = os.path.join(LLVM_DIR, 'projects', 'libcxx')
66LIBCXXABI_DIR = os.path.join(LLVM_DIR, 'projects', 'libcxxabi')
67LLVM_BUILD_TOOLS_DIR = os.path.abspath(
68 os.path.join(LLVM_DIR, '..', 'llvm-build-tools'))
69STAMP_FILE = os.path.normpath(
70 os.path.join(LLVM_DIR, '..', 'llvm-build', 'cr_build_revision'))
Rubin Xu2894c6a2019-02-07 16:01:35 +000071VERSION = '7.0.0'
Ben Murdochf91f0612016-11-29 16:50:11 +000072ANDROID_NDK_DIR = os.path.join(
Rubin Xu2894c6a2019-02-07 16:01:35 +000073 CHROMIUM_DIR, 'third_party', 'android_ndk')
Ben Murdochf91f0612016-11-29 16:50:11 +000074
75# URL for pre-built binaries.
76CDS_URL = os.environ.get('CDS_CLANG_BUCKET_OVERRIDE',
77 'https://commondatastorage.googleapis.com/chromium-browser-clang')
78
79LLVM_REPO_URL='https://llvm.org/svn/llvm-project'
80if 'LLVM_REPO_URL' in os.environ:
81 LLVM_REPO_URL = os.environ['LLVM_REPO_URL']
82
Ben Murdochf91f0612016-11-29 16:50:11 +000083
84
85def DownloadUrl(url, output_file):
86 """Download url into output_file."""
87 CHUNK_SIZE = 4096
88 TOTAL_DOTS = 10
89 num_retries = 3
90 retry_wait_s = 5 # Doubled at each retry.
91
92 while True:
93 try:
94 sys.stdout.write('Downloading %s ' % url)
95 sys.stdout.flush()
96 response = urllib2.urlopen(url)
97 total_size = int(response.info().getheader('Content-Length').strip())
98 bytes_done = 0
99 dots_printed = 0
100 while True:
101 chunk = response.read(CHUNK_SIZE)
102 if not chunk:
103 break
104 output_file.write(chunk)
105 bytes_done += len(chunk)
106 num_dots = TOTAL_DOTS * bytes_done / total_size
107 sys.stdout.write('.' * (num_dots - dots_printed))
108 sys.stdout.flush()
109 dots_printed = num_dots
110 if bytes_done != total_size:
111 raise urllib2.URLError("only got %d of %d bytes" %
112 (bytes_done, total_size))
113 print ' Done.'
114 return
115 except urllib2.URLError as e:
116 sys.stdout.write('\n')
117 print e
118 if num_retries == 0 or isinstance(e, urllib2.HTTPError) and e.code == 404:
119 raise e
120 num_retries -= 1
121 print 'Retrying in %d s ...' % retry_wait_s
122 time.sleep(retry_wait_s)
123 retry_wait_s *= 2
124
125
126def EnsureDirExists(path):
127 if not os.path.exists(path):
Ben Murdochf91f0612016-11-29 16:50:11 +0000128 os.makedirs(path)
129
130
Rubin Xu2894c6a2019-02-07 16:01:35 +0000131def DownloadAndUnpack(url, output_dir, path_prefix=None):
132 """Download an archive from url and extract into output_dir. If path_prefix is
133 not None, only extract files whose paths within the archive start with
134 path_prefix."""
Ben Murdochf91f0612016-11-29 16:50:11 +0000135 with tempfile.TemporaryFile() as f:
136 DownloadUrl(url, f)
137 f.seek(0)
138 EnsureDirExists(output_dir)
139 if url.endswith('.zip'):
Rubin Xu2894c6a2019-02-07 16:01:35 +0000140 assert path_prefix is None
Ben Murdochf91f0612016-11-29 16:50:11 +0000141 zipfile.ZipFile(f).extractall(path=output_dir)
142 else:
Rubin Xu2894c6a2019-02-07 16:01:35 +0000143 t = tarfile.open(mode='r:gz', fileobj=f)
144 members = None
145 if path_prefix is not None:
146 members = [m for m in t.getmembers() if m.name.startswith(path_prefix)]
147 t.extractall(path=output_dir, members=members)
Ben Murdochf91f0612016-11-29 16:50:11 +0000148
149
150def ReadStampFile(path=STAMP_FILE):
151 """Return the contents of the stamp file, or '' if it doesn't exist."""
152 try:
153 with open(path, 'r') as f:
154 return f.read().rstrip()
155 except IOError:
156 return ''
157
158
159def WriteStampFile(s, path=STAMP_FILE):
160 """Write s to the stamp file."""
161 EnsureDirExists(os.path.dirname(path))
162 with open(path, 'w') as f:
163 f.write(s)
164 f.write('\n')
165
166
167def GetSvnRevision(svn_repo):
168 """Returns current revision of the svn repo at svn_repo."""
169 svn_info = subprocess.check_output('svn info ' + svn_repo, shell=True)
170 m = re.search(r'Revision: (\d+)', svn_info)
171 return m.group(1)
172
173
174def RmTree(dir):
175 """Delete dir."""
176 def ChmodAndRetry(func, path, _):
177 # Subversion can leave read-only files around.
178 if not os.access(path, os.W_OK):
179 os.chmod(path, stat.S_IWUSR)
180 return func(path)
181 raise
182
183 shutil.rmtree(dir, onerror=ChmodAndRetry)
184
185
186def RmCmakeCache(dir):
187 """Delete CMake cache related files from dir."""
188 for dirpath, dirs, files in os.walk(dir):
189 if 'CMakeCache.txt' in files:
190 os.remove(os.path.join(dirpath, 'CMakeCache.txt'))
191 if 'CMakeFiles' in dirs:
192 RmTree(os.path.join(dirpath, 'CMakeFiles'))
193
194
195def RunCommand(command, msvc_arch=None, env=None, fail_hard=True):
196 """Run command and return success (True) or failure; or if fail_hard is
197 True, exit on failure. If msvc_arch is set, runs the command in a
198 shell with the msvc tools for that architecture."""
199
200 if msvc_arch and sys.platform == 'win32':
Rubin Xu2894c6a2019-02-07 16:01:35 +0000201 command = [os.path.join(GetWinSDKDir(), 'bin', 'SetEnv.cmd'),
202 "/" + msvc_arch, '&&'] + command
Ben Murdochf91f0612016-11-29 16:50:11 +0000203
204 # https://docs.python.org/2/library/subprocess.html:
205 # "On Unix with shell=True [...] if args is a sequence, the first item
206 # specifies the command string, and any additional items will be treated as
207 # additional arguments to the shell itself. That is to say, Popen does the
208 # equivalent of:
209 # Popen(['/bin/sh', '-c', args[0], args[1], ...])"
210 #
211 # We want to pass additional arguments to command[0], not to the shell,
212 # so manually join everything into a single string.
213 # Annoyingly, for "svn co url c:\path", pipes.quote() thinks that it should
214 # quote c:\path but svn can't handle quoted paths on Windows. Since on
215 # Windows follow-on args are passed to args[0] instead of the shell, don't
216 # do the single-string transformation there.
217 if sys.platform != 'win32':
218 command = ' '.join([pipes.quote(c) for c in command])
219 print 'Running', command
220 if subprocess.call(command, env=env, shell=True) == 0:
221 return True
222 print 'Failed.'
223 if fail_hard:
224 sys.exit(1)
225 return False
226
227
228def CopyFile(src, dst):
229 """Copy a file from src to dst."""
230 print "Copying %s to %s" % (src, dst)
231 shutil.copy(src, dst)
232
233
Rubin Xu2894c6a2019-02-07 16:01:35 +0000234def CopyDirectoryContents(src, dst):
235 """Copy the files from directory src to dst."""
Ben Murdochf91f0612016-11-29 16:50:11 +0000236 dst = os.path.realpath(dst) # realpath() in case dst ends in /..
237 EnsureDirExists(dst)
Rubin Xu2894c6a2019-02-07 16:01:35 +0000238 for f in os.listdir(src):
239 CopyFile(os.path.join(src, f), dst)
Ben Murdochf91f0612016-11-29 16:50:11 +0000240
241
242def Checkout(name, url, dir):
243 """Checkout the SVN module at url into dir. Use name for the log message."""
244 print "Checking out %s r%s into '%s'" % (name, CLANG_REVISION, dir)
245
246 command = ['svn', 'checkout', '--force', url + '@' + CLANG_REVISION, dir]
247 if RunCommand(command, fail_hard=False):
248 return
249
250 if os.path.isdir(dir):
251 print "Removing %s." % (dir)
252 RmTree(dir)
253
254 print "Retrying."
255 RunCommand(command)
256
257
Rubin Xu2894c6a2019-02-07 16:01:35 +0000258def CheckoutRepos(args):
259 if args.skip_checkout:
260 return
261
262 Checkout('LLVM', LLVM_REPO_URL + '/llvm/trunk', LLVM_DIR)
263 Checkout('Clang', LLVM_REPO_URL + '/cfe/trunk', CLANG_DIR)
264 if True:
265 Checkout('LLD', LLVM_REPO_URL + '/lld/trunk', LLD_DIR)
266 elif os.path.exists(LLD_DIR):
267 # In case someone sends a tryjob that temporary adds lld to the checkout,
268 # make sure it's not around on future builds.
269 RmTree(LLD_DIR)
270 Checkout('compiler-rt', LLVM_REPO_URL + '/compiler-rt/trunk', COMPILER_RT_DIR)
271 if sys.platform == 'darwin':
272 # clang needs a libc++ checkout, else -stdlib=libc++ won't find includes
273 # (i.e. this is needed for bootstrap builds).
274 Checkout('libcxx', LLVM_REPO_URL + '/libcxx/trunk', LIBCXX_DIR)
275 # We used to check out libcxxabi on OS X; we no longer need that.
276 if os.path.exists(LIBCXXABI_DIR):
277 RmTree(LIBCXXABI_DIR)
278
279
Ben Murdochf91f0612016-11-29 16:50:11 +0000280def DeleteChromeToolsShim():
281 OLD_SHIM_DIR = os.path.join(LLVM_DIR, 'tools', 'zzz-chrometools')
282 shutil.rmtree(OLD_SHIM_DIR, ignore_errors=True)
283 shutil.rmtree(CHROME_TOOLS_SHIM_DIR, ignore_errors=True)
284
285
286def CreateChromeToolsShim():
287 """Hooks the Chrome tools into the LLVM build.
288
289 Several Chrome tools have dependencies on LLVM/Clang libraries. The LLVM build
290 detects implicit tools in the tools subdirectory, so this helper install a
291 shim CMakeLists.txt that forwards to the real directory for the Chrome tools.
292
293 Note that the shim directory name intentionally has no - or _. The implicit
294 tool detection logic munges them in a weird way."""
295 assert not any(i in os.path.basename(CHROME_TOOLS_SHIM_DIR) for i in '-_')
296 os.mkdir(CHROME_TOOLS_SHIM_DIR)
297 with file(os.path.join(CHROME_TOOLS_SHIM_DIR, 'CMakeLists.txt'), 'w') as f:
298 f.write('# Automatically generated by tools/clang/scripts/update.py. ' +
299 'Do not edit.\n')
300 f.write('# Since tools/clang is located in another directory, use the \n')
301 f.write('# two arg version to specify where build artifacts go. CMake\n')
302 f.write('# disallows reuse of the same binary dir for multiple source\n')
303 f.write('# dirs, so the build artifacts need to go into a subdirectory.\n')
Ben Murdochf91f0612016-11-29 16:50:11 +0000304 f.write('if (CHROMIUM_TOOLS_SRC)\n')
305 f.write(' add_subdirectory(${CHROMIUM_TOOLS_SRC} ' +
306 '${CMAKE_CURRENT_BINARY_DIR}/a)\n')
307 f.write('endif (CHROMIUM_TOOLS_SRC)\n')
308
309
Ben Murdoch62ed6312017-06-06 11:06:27 +0100310def AddSvnToPathOnWin():
311 """Download svn.exe and add it to PATH."""
312 if sys.platform != 'win32':
313 return
314 svn_ver = 'svn-1.6.6-win'
315 svn_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, svn_ver)
316 if not os.path.exists(svn_dir):
317 DownloadAndUnpack(CDS_URL + '/tools/%s.zip' % svn_ver, LLVM_BUILD_TOOLS_DIR)
318 os.environ['PATH'] = svn_dir + os.pathsep + os.environ.get('PATH', '')
319
320
Rubin Xu2894c6a2019-02-07 16:01:35 +0000321def AddCMakeToPath(args):
Ben Murdochf91f0612016-11-29 16:50:11 +0000322 """Download CMake and add it to PATH."""
Rubin Xu2894c6a2019-02-07 16:01:35 +0000323 if args.use_system_cmake:
324 return
325
Ben Murdochf91f0612016-11-29 16:50:11 +0000326 if sys.platform == 'win32':
Rubin Xu2894c6a2019-02-07 16:01:35 +0000327 zip_name = 'cmake-3.12.1-win32-x86.zip'
328 dir_name = ['cmake-3.12.1-win32-x86', 'bin']
329 elif sys.platform == 'darwin':
330 zip_name = 'cmake-3.12.1-Darwin-x86_64.tar.gz'
331 dir_name = ['cmake-3.12.1-Darwin-x86_64', 'CMake.app', 'Contents', 'bin']
Ben Murdochf91f0612016-11-29 16:50:11 +0000332 else:
Rubin Xu2894c6a2019-02-07 16:01:35 +0000333 zip_name = 'cmake-3.12.1-Linux-x86_64.tar.gz'
334 dir_name = ['cmake-3.12.1-Linux-x86_64', 'bin']
335
336 cmake_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, *dir_name)
Ben Murdochf91f0612016-11-29 16:50:11 +0000337 if not os.path.exists(cmake_dir):
338 DownloadAndUnpack(CDS_URL + '/tools/' + zip_name, LLVM_BUILD_TOOLS_DIR)
339 os.environ['PATH'] = cmake_dir + os.pathsep + os.environ.get('PATH', '')
340
341
342def AddGnuWinToPath():
343 """Download some GNU win tools and add them to PATH."""
344 if sys.platform != 'win32':
345 return
346
347 gnuwin_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, 'gnuwin')
Rubin Xu2894c6a2019-02-07 16:01:35 +0000348 GNUWIN_VERSION = '8'
Ben Murdochf91f0612016-11-29 16:50:11 +0000349 GNUWIN_STAMP = os.path.join(gnuwin_dir, 'stamp')
350 if ReadStampFile(GNUWIN_STAMP) == GNUWIN_VERSION:
351 print 'GNU Win tools already up to date.'
352 else:
353 zip_name = 'gnuwin-%s.zip' % GNUWIN_VERSION
354 DownloadAndUnpack(CDS_URL + '/tools/' + zip_name, LLVM_BUILD_TOOLS_DIR)
355 WriteStampFile(GNUWIN_VERSION, GNUWIN_STAMP)
356
357 os.environ['PATH'] = gnuwin_dir + os.pathsep + os.environ.get('PATH', '')
358
359
Rubin Xu2894c6a2019-02-07 16:01:35 +0000360win_sdk_dir = None
361dia_dll = None
362def GetWinSDKDir():
363 """Get the location of the current SDK. Sets dia_dll as a side-effect."""
364 global win_sdk_dir
365 global dia_dll
366 if win_sdk_dir:
367 return win_sdk_dir
Ben Murdochf91f0612016-11-29 16:50:11 +0000368
Rubin Xu2894c6a2019-02-07 16:01:35 +0000369 # Bump after VC updates.
370 DIA_DLL = {
371 '2013': 'msdia120.dll',
372 '2015': 'msdia140.dll',
373 '2017': 'msdia140.dll',
374 }
375
376 # Don't let vs_toolchain overwrite our environment.
377 environ_bak = os.environ
378
Ben Murdochf91f0612016-11-29 16:50:11 +0000379 sys.path.append(os.path.join(CHROMIUM_DIR, 'build'))
380 import vs_toolchain
Rubin Xu2894c6a2019-02-07 16:01:35 +0000381 win_sdk_dir = vs_toolchain.SetEnvironmentAndGetSDKDir()
382 msvs_version = vs_toolchain.GetVisualStudioVersion()
Ben Murdochf91f0612016-11-29 16:50:11 +0000383
Rubin Xu2894c6a2019-02-07 16:01:35 +0000384 if bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1'))):
385 dia_path = os.path.join(win_sdk_dir, '..', 'DIA SDK', 'bin', 'amd64')
386 else:
387 if 'GYP_MSVS_OVERRIDE_PATH' not in os.environ:
388 vs_path = vs_toolchain.DetectVisualStudioPath()
389 else:
390 vs_path = os.environ['GYP_MSVS_OVERRIDE_PATH']
391 dia_path = os.path.join(vs_path, 'DIA SDK', 'bin', 'amd64')
392
393 dia_dll = os.path.join(dia_path, DIA_DLL[msvs_version])
394
395 os.environ = environ_bak
396 return win_sdk_dir
Ben Murdochf91f0612016-11-29 16:50:11 +0000397
398
399def CopyDiaDllTo(target_dir):
400 # This script always wants to use the 64-bit msdia*.dll.
Rubin Xu2894c6a2019-02-07 16:01:35 +0000401 GetWinSDKDir()
Ben Murdochf91f0612016-11-29 16:50:11 +0000402 CopyFile(dia_dll, target_dir)
403
404
405def VeryifyVersionOfBuiltClangMatchesVERSION():
406 """Checks that `clang --version` outputs VERSION. If this fails, VERSION
407 in this file is out-of-date and needs to be updated (possibly in an
408 `if use_head_revision:` block in main() first)."""
409 clang = os.path.join(LLVM_BUILD_DIR, 'bin', 'clang')
410 if sys.platform == 'win32':
411 # TODO: Parse `clang-cl /?` output for built clang's version and check that
412 # to check the binary we're actually shipping? But clang-cl.exe is just
413 # a copy of clang.exe, so this does check the same thing.
414 clang += '.exe'
415 version_out = subprocess.check_output([clang, '--version'])
416 version_out = re.match(r'clang version ([0-9.]+)', version_out).group(1)
417 if version_out != VERSION:
418 print ('unexpected clang version %s (not %s), update VERSION in update.py'
419 % (version_out, VERSION))
420 sys.exit(1)
421
422
Rubin Xu2894c6a2019-02-07 16:01:35 +0000423def GetPlatformUrlPrefix(platform):
424 if platform == 'win32' or platform == 'cygwin':
425 return CDS_URL + '/Win/'
426 if platform == 'darwin':
427 return CDS_URL + '/Mac/'
428 assert platform.startswith('linux')
429 return CDS_URL + '/Linux_x64/'
430
431
432def DownloadAndUnpackClangPackage(platform, runtimes_only=False):
433 cds_file = "clang-%s.tgz" % PACKAGE_VERSION
434 cds_full_url = GetPlatformUrlPrefix(platform) + cds_file
435 try:
436 path_prefix = None
437 if runtimes_only:
438 path_prefix = 'lib/clang/' + VERSION + '/lib/'
439 DownloadAndUnpack(cds_full_url, LLVM_BUILD_DIR, path_prefix)
440 except urllib2.URLError:
441 print 'Failed to download prebuilt clang %s' % cds_file
442 print 'Use --force-local-build if you want to build locally.'
443 print 'Exiting.'
444 sys.exit(1)
445
446
Ben Murdochf91f0612016-11-29 16:50:11 +0000447def UpdateClang(args):
Rubin Xu2894c6a2019-02-07 16:01:35 +0000448 # Read target_os from .gclient so we know which non-native runtimes we need.
449 # TODO(pcc): See if we can download just the runtimes instead of the entire
450 # clang package, and do that from DEPS instead of here.
451 target_os = []
452 try:
453 env = {}
454 execfile(GCLIENT_CONFIG, env, env)
455 target_os = env.get('target_os', target_os)
456 except:
457 pass
Ben Murdochf91f0612016-11-29 16:50:11 +0000458
Rubin Xu2894c6a2019-02-07 16:01:35 +0000459 expected_stamp = ','.join([PACKAGE_VERSION] + target_os)
460 if ReadStampFile() == expected_stamp and not args.force_local_build:
461 return 0
Ben Murdochf91f0612016-11-29 16:50:11 +0000462
463 # Reset the stamp file in case the build is unsuccessful.
464 WriteStampFile('')
465
466 if not args.force_local_build:
Ben Murdochf91f0612016-11-29 16:50:11 +0000467 if os.path.exists(LLVM_BUILD_DIR):
468 RmTree(LLVM_BUILD_DIR)
Rubin Xu2894c6a2019-02-07 16:01:35 +0000469
470 DownloadAndUnpackClangPackage(sys.platform)
471 if 'win' in target_os:
472 DownloadAndUnpackClangPackage('win32', runtimes_only=True)
473 if sys.platform == 'win32':
474 CopyDiaDllTo(os.path.join(LLVM_BUILD_DIR, 'bin'))
475 WriteStampFile(expected_stamp)
476 return 0
Ben Murdochf91f0612016-11-29 16:50:11 +0000477
478 if args.with_android and not os.path.exists(ANDROID_NDK_DIR):
479 print 'Android NDK not found at ' + ANDROID_NDK_DIR
480 print 'The Android NDK is needed to build a Clang whose -fsanitize=address'
481 print 'works on Android. See '
482 print 'https://www.chromium.org/developers/how-tos/android-build-instructions'
483 print 'for how to install the NDK, or pass --without-android.'
484 return 1
485
Rubin Xu2894c6a2019-02-07 16:01:35 +0000486 print 'Locally building Clang %s...' % PACKAGE_VERSION
487
488 if use_head_revision:
489 # TODO(hans): Trunk version was updated; remove after the next roll.
490 # Remove the old lib dir.
491 old_lib_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang', '7.0.0')
492 if (os.path.isdir(old_lib_dir)):
493 print 'Removing old lib dir: %s' % old_lib_dir
494 RmTree(old_lib_dir)
495
496 AddCMakeToPath(args)
Ben Murdochf91f0612016-11-29 16:50:11 +0000497 AddGnuWinToPath()
498
499 DeleteChromeToolsShim()
500
Rubin Xu2894c6a2019-02-07 16:01:35 +0000501 CheckoutRepos(args)
502
503 if args.skip_build:
504 return
Ben Murdochf91f0612016-11-29 16:50:11 +0000505
506 cc, cxx = None, None
507 libstdcpp = None
Ben Murdochf91f0612016-11-29 16:50:11 +0000508
509 cflags = []
510 cxxflags = []
511 ldflags = []
512
513 base_cmake_args = ['-GNinja',
514 '-DCMAKE_BUILD_TYPE=Release',
515 '-DLLVM_ENABLE_ASSERTIONS=ON',
Rubin Xu2894c6a2019-02-07 16:01:35 +0000516 '-DLLVM_ENABLE_TERMINFO=OFF',
Ben Murdochf91f0612016-11-29 16:50:11 +0000517 # Statically link MSVCRT to avoid DLL dependencies.
518 '-DLLVM_USE_CRT_RELEASE=MT',
519 ]
520
Rubin Xu2894c6a2019-02-07 16:01:35 +0000521 if sys.platform != 'win32':
522 # libxml2 is required by the Win manifest merging tool used in cross-builds.
523 base_cmake_args.append('-DLLVM_ENABLE_LIBXML2=FORCE_ON')
Ben Murdochf91f0612016-11-29 16:50:11 +0000524
525 if args.bootstrap:
526 print 'Building bootstrap compiler'
527 EnsureDirExists(LLVM_BOOTSTRAP_DIR)
528 os.chdir(LLVM_BOOTSTRAP_DIR)
529 bootstrap_args = base_cmake_args + [
Rubin Xu2894c6a2019-02-07 16:01:35 +0000530 '-DLLVM_TARGETS_TO_BUILD=X86;ARM;AArch64',
Ben Murdochf91f0612016-11-29 16:50:11 +0000531 '-DCMAKE_INSTALL_PREFIX=' + LLVM_BOOTSTRAP_INSTALL_DIR,
532 '-DCMAKE_C_FLAGS=' + ' '.join(cflags),
533 '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags),
534 ]
535 if cc is not None: bootstrap_args.append('-DCMAKE_C_COMPILER=' + cc)
536 if cxx is not None: bootstrap_args.append('-DCMAKE_CXX_COMPILER=' + cxx)
537 RmCmakeCache('.')
538 RunCommand(['cmake'] + bootstrap_args + [LLVM_DIR], msvc_arch='x64')
539 RunCommand(['ninja'], msvc_arch='x64')
540 if args.run_tests:
541 if sys.platform == 'win32':
542 CopyDiaDllTo(os.path.join(LLVM_BOOTSTRAP_DIR, 'bin'))
543 RunCommand(['ninja', 'check-all'], msvc_arch='x64')
544 RunCommand(['ninja', 'install'], msvc_arch='x64')
Ben Murdochf91f0612016-11-29 16:50:11 +0000545
546 if sys.platform == 'win32':
547 cc = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang-cl.exe')
548 cxx = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang-cl.exe')
549 # CMake has a hard time with backslashes in compiler paths:
550 # https://stackoverflow.com/questions/13050827
551 cc = cc.replace('\\', '/')
552 cxx = cxx.replace('\\', '/')
553 else:
554 cc = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang')
555 cxx = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang++')
556
Ben Murdochf91f0612016-11-29 16:50:11 +0000557 print 'Building final compiler'
558
Ben Murdochf91f0612016-11-29 16:50:11 +0000559 # LLVM uses C++11 starting in llvm 3.5. On Linux, this means libstdc++4.7+ is
560 # needed, on OS X it requires libc++. clang only automatically links to libc++
561 # when targeting OS X 10.9+, so add stdlib=libc++ explicitly so clang can run
562 # on OS X versions as old as 10.7.
563 deployment_target = ''
564
565 if sys.platform == 'darwin' and args.bootstrap:
566 # When building on 10.9, /usr/include usually doesn't exist, and while
567 # Xcode's clang automatically sets a sysroot, self-built clangs don't.
568 cflags = ['-isysroot', subprocess.check_output(
569 ['xcrun', '--show-sdk-path']).rstrip()]
570 cxxflags = ['-stdlib=libc++'] + cflags
571 ldflags += ['-stdlib=libc++']
572 deployment_target = '10.7'
573 # Running libc++ tests takes a long time. Since it was only needed for
574 # the install step above, don't build it as part of the main build.
575 # This makes running package.py over 10% faster (30 min instead of 34 min)
576 RmTree(LIBCXX_DIR)
577
Ben Murdochf91f0612016-11-29 16:50:11 +0000578
579 # If building at head, define a macro that plugins can use for #ifdefing
580 # out code that builds at head, but not at CLANG_REVISION or vice versa.
581 if use_head_revision:
582 cflags += ['-DLLVM_FORCE_HEAD_REVISION']
583 cxxflags += ['-DLLVM_FORCE_HEAD_REVISION']
584
Rubin Xu2894c6a2019-02-07 16:01:35 +0000585 # Build PDBs for archival on Windows. Don't use RelWithDebInfo since it
586 # has different optimization defaults than Release.
587 # Also disable stack cookies (/GS-) for performance.
588 if sys.platform == 'win32':
589 cflags += ['/Zi', '/GS-']
590 cxxflags += ['/Zi', '/GS-']
591 ldflags += ['/DEBUG', '/OPT:REF', '/OPT:ICF']
Ben Murdochf91f0612016-11-29 16:50:11 +0000592
593 deployment_env = None
594 if deployment_target:
595 deployment_env = os.environ.copy()
596 deployment_env['MACOSX_DEPLOYMENT_TARGET'] = deployment_target
597
Rubin Xu2894c6a2019-02-07 16:01:35 +0000598 # Build lld and code coverage tools. This is done separately from the rest of
599 # the build because these tools require threading support.
600 tools_with_threading = [ 'lld', 'llvm-cov', 'llvm-profdata' ]
601 print 'Building the following tools with threading support: %s' % (
602 str(tools_with_threading))
603
604 if os.path.exists(THREADS_ENABLED_BUILD_DIR):
605 RmTree(THREADS_ENABLED_BUILD_DIR)
606 EnsureDirExists(THREADS_ENABLED_BUILD_DIR)
607 os.chdir(THREADS_ENABLED_BUILD_DIR)
608
609 threads_enabled_cmake_args = base_cmake_args + [
610 '-DCMAKE_C_FLAGS=' + ' '.join(cflags),
611 '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags),
612 '-DCMAKE_EXE_LINKER_FLAGS=' + ' '.join(ldflags),
613 '-DCMAKE_SHARED_LINKER_FLAGS=' + ' '.join(ldflags),
614 '-DCMAKE_MODULE_LINKER_FLAGS=' + ' '.join(ldflags)]
615 if cc is not None:
616 threads_enabled_cmake_args.append('-DCMAKE_C_COMPILER=' + cc)
617 if cxx is not None:
618 threads_enabled_cmake_args.append('-DCMAKE_CXX_COMPILER=' + cxx)
619
620 if args.lto_lld:
621 # Build lld with LTO. That speeds up the linker by ~10%.
622 # We only use LTO for Linux now.
623 #
624 # The linker expects all archive members to have symbol tables, so the
625 # archiver needs to be able to create symbol tables for bitcode files.
626 # GNU ar and ranlib don't understand bitcode files, but llvm-ar and
627 # llvm-ranlib do, so use them.
628 ar = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'llvm-ar')
629 ranlib = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'llvm-ranlib')
630 threads_enabled_cmake_args += [
631 '-DCMAKE_AR=' + ar,
632 '-DCMAKE_RANLIB=' + ranlib,
633 '-DLLVM_ENABLE_LTO=thin',
634 '-DLLVM_USE_LINKER=lld']
635
636 RmCmakeCache('.')
637 RunCommand(['cmake'] + threads_enabled_cmake_args + [LLVM_DIR],
638 msvc_arch='x64', env=deployment_env)
639 RunCommand(['ninja'] + tools_with_threading, msvc_arch='x64')
640
641 # Build clang and other tools.
642 CreateChromeToolsShim()
643
Ben Murdochf91f0612016-11-29 16:50:11 +0000644 cmake_args = []
645 # TODO(thakis): Unconditionally append this to base_cmake_args instead once
646 # compiler-rt can build with clang-cl on Windows (http://llvm.org/PR23698)
647 cc_args = base_cmake_args if sys.platform != 'win32' else cmake_args
648 if cc is not None: cc_args.append('-DCMAKE_C_COMPILER=' + cc)
649 if cxx is not None: cc_args.append('-DCMAKE_CXX_COMPILER=' + cxx)
Rubin Xu2894c6a2019-02-07 16:01:35 +0000650 default_tools = ['plugins', 'blink_gc_plugin', 'translation_unit']
651 chrome_tools = list(set(default_tools + args.extra_tools))
Ben Murdochf91f0612016-11-29 16:50:11 +0000652 cmake_args += base_cmake_args + [
Rubin Xu2894c6a2019-02-07 16:01:35 +0000653 '-DLLVM_ENABLE_THREADS=OFF',
Ben Murdochf91f0612016-11-29 16:50:11 +0000654 '-DCMAKE_C_FLAGS=' + ' '.join(cflags),
655 '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags),
656 '-DCMAKE_EXE_LINKER_FLAGS=' + ' '.join(ldflags),
657 '-DCMAKE_SHARED_LINKER_FLAGS=' + ' '.join(ldflags),
658 '-DCMAKE_MODULE_LINKER_FLAGS=' + ' '.join(ldflags),
659 '-DCMAKE_INSTALL_PREFIX=' + LLVM_BUILD_DIR,
Ben Murdochf91f0612016-11-29 16:50:11 +0000660 '-DCHROMIUM_TOOLS_SRC=%s' % os.path.join(CHROMIUM_DIR, 'tools', 'clang'),
Ben Murdoch62ed6312017-06-06 11:06:27 +0100661 '-DCHROMIUM_TOOLS=%s' % ';'.join(chrome_tools)]
Ben Murdochf91f0612016-11-29 16:50:11 +0000662
663 EnsureDirExists(LLVM_BUILD_DIR)
664 os.chdir(LLVM_BUILD_DIR)
665 RmCmakeCache('.')
666 RunCommand(['cmake'] + cmake_args + [LLVM_DIR],
667 msvc_arch='x64', env=deployment_env)
Ben Murdochf91f0612016-11-29 16:50:11 +0000668 RunCommand(['ninja'], msvc_arch='x64')
669
Rubin Xu2894c6a2019-02-07 16:01:35 +0000670 # Copy in the threaded versions of lld and other tools.
671 if sys.platform == 'win32':
672 CopyFile(os.path.join(THREADS_ENABLED_BUILD_DIR, 'bin', 'lld-link.exe'),
673 os.path.join(LLVM_BUILD_DIR, 'bin'))
674 CopyFile(os.path.join(THREADS_ENABLED_BUILD_DIR, 'bin', 'lld.pdb'),
675 os.path.join(LLVM_BUILD_DIR, 'bin'))
676 else:
677 for tool in tools_with_threading:
678 CopyFile(os.path.join(THREADS_ENABLED_BUILD_DIR, 'bin', tool),
679 os.path.join(LLVM_BUILD_DIR, 'bin'))
680
Ben Murdoch62ed6312017-06-06 11:06:27 +0100681 if chrome_tools:
Ben Murdochf91f0612016-11-29 16:50:11 +0000682 # If any Chromium tools were built, install those now.
683 RunCommand(['ninja', 'cr-install'], msvc_arch='x64')
684
Ben Murdochf91f0612016-11-29 16:50:11 +0000685 VeryifyVersionOfBuiltClangMatchesVERSION()
686
687 # Do an out-of-tree build of compiler-rt.
688 # On Windows, this is used to get the 32-bit ASan run-time.
689 # TODO(hans): Remove once the regular build above produces this.
690 # On Mac and Linux, this is used to get the regular 64-bit run-time.
691 # Do a clobbered build due to cmake changes.
692 if os.path.isdir(COMPILER_RT_BUILD_DIR):
693 RmTree(COMPILER_RT_BUILD_DIR)
694 os.makedirs(COMPILER_RT_BUILD_DIR)
695 os.chdir(COMPILER_RT_BUILD_DIR)
696 # TODO(thakis): Add this once compiler-rt can build with clang-cl (see
697 # above).
698 #if args.bootstrap and sys.platform == 'win32':
699 # The bootstrap compiler produces 64-bit binaries by default.
700 #cflags += ['-m32']
701 #cxxflags += ['-m32']
702 compiler_rt_args = base_cmake_args + [
Rubin Xu2894c6a2019-02-07 16:01:35 +0000703 '-DLLVM_ENABLE_THREADS=OFF',
Ben Murdochf91f0612016-11-29 16:50:11 +0000704 '-DCMAKE_C_FLAGS=' + ' '.join(cflags),
705 '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags)]
706 if sys.platform == 'darwin':
707 compiler_rt_args += ['-DCOMPILER_RT_ENABLE_IOS=ON']
708 if sys.platform != 'win32':
709 compiler_rt_args += ['-DLLVM_CONFIG_PATH=' +
710 os.path.join(LLVM_BUILD_DIR, 'bin', 'llvm-config'),
711 '-DSANITIZER_MIN_OSX_VERSION="10.7"']
712 # compiler-rt is part of the llvm checkout on Windows but a stand-alone
713 # directory elsewhere, see the TODO above COMPILER_RT_DIR.
714 RmCmakeCache('.')
715 RunCommand(['cmake'] + compiler_rt_args +
716 [LLVM_DIR if sys.platform == 'win32' else COMPILER_RT_DIR],
717 msvc_arch='x86', env=deployment_env)
718 RunCommand(['ninja', 'compiler-rt'], msvc_arch='x86')
Rubin Xu2894c6a2019-02-07 16:01:35 +0000719 if sys.platform != 'win32':
720 RunCommand(['ninja', 'fuzzer'])
Ben Murdochf91f0612016-11-29 16:50:11 +0000721
722 # Copy select output to the main tree.
723 # TODO(hans): Make this (and the .gypi and .isolate files) version number
724 # independent.
725 if sys.platform == 'win32':
726 platform = 'windows'
727 elif sys.platform == 'darwin':
728 platform = 'darwin'
729 else:
730 assert sys.platform.startswith('linux')
731 platform = 'linux'
Rubin Xu2894c6a2019-02-07 16:01:35 +0000732 rt_lib_src_dir = os.path.join(COMPILER_RT_BUILD_DIR, 'lib', platform)
Ben Murdochf91f0612016-11-29 16:50:11 +0000733 if sys.platform == 'win32':
734 # TODO(thakis): This too is due to compiler-rt being part of the checkout
735 # on Windows, see TODO above COMPILER_RT_DIR.
Rubin Xu2894c6a2019-02-07 16:01:35 +0000736 rt_lib_src_dir = os.path.join(COMPILER_RT_BUILD_DIR, 'lib', 'clang',
737 VERSION, 'lib', platform)
738 rt_lib_dst_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang', VERSION, 'lib',
739 platform)
Ben Murdochf91f0612016-11-29 16:50:11 +0000740 # Blacklists:
Rubin Xu2894c6a2019-02-07 16:01:35 +0000741 CopyDirectoryContents(os.path.join(rt_lib_src_dir, '..', '..', 'share'),
742 os.path.join(rt_lib_dst_dir, '..', '..', 'share'))
Ben Murdochf91f0612016-11-29 16:50:11 +0000743 # Headers:
744 if sys.platform != 'win32':
745 CopyDirectoryContents(
746 os.path.join(COMPILER_RT_BUILD_DIR, 'include/sanitizer'),
747 os.path.join(LLVM_BUILD_DIR, 'lib/clang', VERSION, 'include/sanitizer'))
748 # Static and dynamic libraries:
Rubin Xu2894c6a2019-02-07 16:01:35 +0000749 CopyDirectoryContents(rt_lib_src_dir, rt_lib_dst_dir)
Ben Murdochf91f0612016-11-29 16:50:11 +0000750 if sys.platform == 'darwin':
Rubin Xu2894c6a2019-02-07 16:01:35 +0000751 for dylib in glob.glob(os.path.join(rt_lib_dst_dir, '*.dylib')):
Ben Murdochf91f0612016-11-29 16:50:11 +0000752 # Fix LC_ID_DYLIB for the ASan dynamic libraries to be relative to
753 # @executable_path.
754 # TODO(glider): this is transitional. We'll need to fix the dylib
755 # name either in our build system, or in Clang. See also
756 # http://crbug.com/344836.
757 subprocess.call(['install_name_tool', '-id',
758 '@executable_path/' + os.path.basename(dylib), dylib])
759
Ben Murdochf91f0612016-11-29 16:50:11 +0000760 if args.with_android:
761 make_toolchain = os.path.join(
762 ANDROID_NDK_DIR, 'build', 'tools', 'make_standalone_toolchain.py')
763 for target_arch in ['aarch64', 'arm', 'i686']:
764 # Make standalone Android toolchain for target_arch.
765 toolchain_dir = os.path.join(
766 LLVM_BUILD_DIR, 'android-toolchain-' + target_arch)
Rubin Xu2894c6a2019-02-07 16:01:35 +0000767 api_level = '21' if target_arch == 'aarch64' else '19'
Ben Murdochf91f0612016-11-29 16:50:11 +0000768 RunCommand([
769 make_toolchain,
Rubin Xu2894c6a2019-02-07 16:01:35 +0000770 '--api=' + api_level,
Ben Murdochf91f0612016-11-29 16:50:11 +0000771 '--force',
772 '--install-dir=%s' % toolchain_dir,
Rubin Xu2894c6a2019-02-07 16:01:35 +0000773 '--stl=libc++',
Ben Murdochf91f0612016-11-29 16:50:11 +0000774 '--arch=' + {
775 'aarch64': 'arm64',
776 'arm': 'arm',
777 'i686': 'x86',
778 }[target_arch]])
Ben Murdochf91f0612016-11-29 16:50:11 +0000779
Rubin Xu2894c6a2019-02-07 16:01:35 +0000780 # Build compiler-rt runtimes needed for Android in a separate build tree.
Ben Murdochf91f0612016-11-29 16:50:11 +0000781 build_dir = os.path.join(LLVM_BUILD_DIR, 'android-' + target_arch)
782 if not os.path.exists(build_dir):
783 os.mkdir(os.path.join(build_dir))
784 os.chdir(build_dir)
Rubin Xu2894c6a2019-02-07 16:01:35 +0000785 target_triple = target_arch
786 abi_libs = 'c++abi'
787 if target_arch == 'arm':
788 target_triple = 'armv7'
789 abi_libs += ';unwind'
790 target_triple += '-linux-android' + api_level
791 cflags = ['--target=%s' % target_triple,
Ben Murdochf91f0612016-11-29 16:50:11 +0000792 '--sysroot=%s/sysroot' % toolchain_dir,
793 '-B%s' % toolchain_dir]
794 android_args = base_cmake_args + [
Rubin Xu2894c6a2019-02-07 16:01:35 +0000795 '-DLLVM_ENABLE_THREADS=OFF',
Ben Murdochf91f0612016-11-29 16:50:11 +0000796 '-DCMAKE_C_COMPILER=' + os.path.join(LLVM_BUILD_DIR, 'bin/clang'),
797 '-DCMAKE_CXX_COMPILER=' + os.path.join(LLVM_BUILD_DIR, 'bin/clang++'),
798 '-DLLVM_CONFIG_PATH=' + os.path.join(LLVM_BUILD_DIR, 'bin/llvm-config'),
799 '-DCMAKE_C_FLAGS=' + ' '.join(cflags),
800 '-DCMAKE_CXX_FLAGS=' + ' '.join(cflags),
Rubin Xu2894c6a2019-02-07 16:01:35 +0000801 '-DSANITIZER_CXX_ABI=none',
802 '-DSANITIZER_CXX_ABI_LIBRARY=' + abi_libs,
803 '-DCMAKE_SHARED_LINKER_FLAGS=-Wl,-u__cxa_demangle',
Ben Murdochf91f0612016-11-29 16:50:11 +0000804 '-DANDROID=1']
805 RmCmakeCache('.')
806 RunCommand(['cmake'] + android_args + [COMPILER_RT_DIR])
Rubin Xu2894c6a2019-02-07 16:01:35 +0000807 RunCommand(['ninja', 'asan', 'ubsan', 'profile'])
Ben Murdochf91f0612016-11-29 16:50:11 +0000808
Rubin Xu2894c6a2019-02-07 16:01:35 +0000809 # And copy them into the main build tree.
810 asan_lib_path_format = 'lib/linux/libclang_rt.asan-{0}-android.so'
811 libs_want = [
812 asan_lib_path_format,
813 'lib/linux/libclang_rt.ubsan_standalone-{0}-android.so',
814 'lib/linux/libclang_rt.profile-{0}-android.a',
815 ]
816 for arch in ['aarch64', 'arm']:
817 for p in libs_want:
818 lib_path = os.path.join(build_dir, p.format(arch))
819 if os.path.exists(lib_path):
820 shutil.copy(lib_path, rt_lib_dst_dir)
821
822 # We also use ASan i686 build for fuzzing.
823 lib_path = os.path.join(build_dir, asan_lib_path_format.format('i686'))
824 if os.path.exists(lib_path):
825 shutil.copy(lib_path, rt_lib_dst_dir)
Ben Murdochf91f0612016-11-29 16:50:11 +0000826
827 # Run tests.
828 if args.run_tests or use_head_revision:
829 os.chdir(LLVM_BUILD_DIR)
830 RunCommand(['ninja', 'cr-check-all'], msvc_arch='x64')
831 if args.run_tests:
832 if sys.platform == 'win32':
833 CopyDiaDllTo(os.path.join(LLVM_BUILD_DIR, 'bin'))
834 os.chdir(LLVM_BUILD_DIR)
835 RunCommand(['ninja', 'check-all'], msvc_arch='x64')
836
837 WriteStampFile(PACKAGE_VERSION)
838 print 'Clang update was successful.'
839 return 0
840
841
842def main():
843 parser = argparse.ArgumentParser(description='Build Clang.')
844 parser.add_argument('--bootstrap', action='store_true',
845 help='first build clang with CC, then with itself.')
Rubin Xu2894c6a2019-02-07 16:01:35 +0000846 # TODO(phajdan.jr): remove --if-needed after fixing callers. It's no-op.
Ben Murdochf91f0612016-11-29 16:50:11 +0000847 parser.add_argument('--if-needed', action='store_true',
848 help="run only if the script thinks clang is needed")
849 parser.add_argument('--force-local-build', action='store_true',
850 help="don't try to download prebuild binaries")
851 parser.add_argument('--gcc-toolchain', help='set the version for which gcc '
852 'version be used for building; --gcc-toolchain=/opt/foo '
853 'picks /opt/foo/bin/gcc')
Rubin Xu2894c6a2019-02-07 16:01:35 +0000854 parser.add_argument('--lto-lld', action='store_true',
855 help='build lld with LTO')
Ben Murdochf91f0612016-11-29 16:50:11 +0000856 parser.add_argument('--llvm-force-head-revision', action='store_true',
857 help=('use the revision in the repo when printing '
858 'the revision'))
859 parser.add_argument('--print-revision', action='store_true',
860 help='print current clang revision and exit.')
861 parser.add_argument('--print-clang-version', action='store_true',
862 help='print current clang version (e.g. x.y.z) and exit.')
863 parser.add_argument('--run-tests', action='store_true',
864 help='run tests after building; only for local builds')
Rubin Xu2894c6a2019-02-07 16:01:35 +0000865 parser.add_argument('--skip-build', action='store_true',
866 help='do not build anything')
867 parser.add_argument('--skip-checkout', action='store_true',
868 help='do not create or update any checkouts')
Ben Murdoch62ed6312017-06-06 11:06:27 +0100869 parser.add_argument('--extra-tools', nargs='*', default=[],
870 help='select additional chrome tools to build')
Rubin Xu2894c6a2019-02-07 16:01:35 +0000871 parser.add_argument('--use-system-cmake', action='store_true',
872 help='use the cmake from PATH instead of downloading '
873 'and using prebuilt cmake binaries')
874 parser.add_argument('--verify-version',
875 help='verify that clang has the passed-in version')
Ben Murdochf91f0612016-11-29 16:50:11 +0000876 parser.add_argument('--without-android', action='store_false',
877 help='don\'t build Android ASan runtime (linux only)',
878 dest='with_android',
879 default=sys.platform.startswith('linux'))
880 args = parser.parse_args()
881
Rubin Xu2894c6a2019-02-07 16:01:35 +0000882 if args.lto_lld and not args.bootstrap:
883 print '--lto-lld requires --bootstrap'
Ben Murdochf91f0612016-11-29 16:50:11 +0000884 return 1
Rubin Xu2894c6a2019-02-07 16:01:35 +0000885 if args.lto_lld and not sys.platform.startswith('linux'):
886 print '--lto-lld is only effective on Linux. Ignoring the option.'
887 args.lto_lld = False
Ben Murdochf91f0612016-11-29 16:50:11 +0000888
Rubin Xu2894c6a2019-02-07 16:01:35 +0000889 # Get svn if we're going to use it to check the revision or do a local build.
890 if (use_head_revision or args.llvm_force_head_revision or
891 args.force_local_build):
892 AddSvnToPathOnWin()
Ben Murdochf91f0612016-11-29 16:50:11 +0000893
Ben Murdoch62ed6312017-06-06 11:06:27 +0100894 if use_head_revision:
Rubin Xu2894c6a2019-02-07 16:01:35 +0000895 # TODO(hans): Trunk version was updated; remove after the next roll.
Ben Murdoch62ed6312017-06-06 11:06:27 +0100896 global VERSION
Rubin Xu2894c6a2019-02-07 16:01:35 +0000897 VERSION = '8.0.0'
898
899 if args.verify_version and args.verify_version != VERSION:
900 print 'VERSION is %s but --verify-version argument was %s, exiting.' % (
901 VERSION, args.verify_version)
902 print 'clang_version in build/toolchain/toolchain.gni is likely outdated.'
903 return 1
Ben Murdoch62ed6312017-06-06 11:06:27 +0100904
Ben Murdochf91f0612016-11-29 16:50:11 +0000905 global CLANG_REVISION, PACKAGE_VERSION
906 if args.print_revision:
907 if use_head_revision or args.llvm_force_head_revision:
908 print GetSvnRevision(LLVM_DIR)
909 else:
910 print PACKAGE_VERSION
911 return 0
912
913 if args.print_clang_version:
914 sys.stdout.write(VERSION)
915 return 0
916
917 # Don't buffer stdout, so that print statements are immediately flushed.
918 # Do this only after --print-revision has been handled, else we'll get
919 # an error message when this script is run from gn for some reason.
920 sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
921
922 if use_head_revision:
923 # Use a real revision number rather than HEAD to make sure that the stamp
924 # file logic works.
925 CLANG_REVISION = GetSvnRevision(LLVM_REPO_URL)
926 PACKAGE_VERSION = CLANG_REVISION + '-0'
927
928 args.force_local_build = True
929 if 'OS=android' not in os.environ.get('GYP_DEFINES', ''):
930 # Only build the Android ASan rt on ToT bots when targetting Android.
931 args.with_android = False
932
933 return UpdateClang(args)
934
935
936if __name__ == '__main__':
937 sys.exit(main())