Advertisement
Guest User

depot_tools/chromium/src/tools/clang/scripts/build.py

a guest
Aug 22nd, 2021
130
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 49.24 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # Copyright 2019 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 build clang binaries. It is used by package.py to
  7. create the prebuilt binaries downloaded by update.py and used by developers.
  8.  
  9. The expectation is that update.py downloads prebuilt binaries for everyone, and
  10. nobody should run this script as part of normal development.
  11. """
  12.  
  13. from __future__ import print_function
  14.  
  15. import argparse
  16. import glob
  17. import io
  18. import json
  19. import os
  20. import pipes
  21. import platform
  22. import re
  23. import shutil
  24. import subprocess
  25. import sys
  26.  
  27. from update import (CDS_URL, CHROMIUM_DIR, CLANG_REVISION, LLVM_BUILD_DIR,
  28. FORCE_HEAD_REVISION_FILE, PACKAGE_VERSION, RELEASE_VERSION,
  29. STAMP_FILE, DownloadUrl, DownloadAndUnpack, EnsureDirExists,
  30. ReadStampFile, RmTree, WriteStampFile)
  31.  
  32. # Path constants. (All of these should be absolute paths.)
  33. THIRD_PARTY_DIR = os.path.join(CHROMIUM_DIR, 'third_party')
  34. LLVM_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm')
  35. COMPILER_RT_DIR = os.path.join(LLVM_DIR, 'compiler-rt')
  36. LLVM_BOOTSTRAP_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm-bootstrap')
  37. LLVM_BOOTSTRAP_INSTALL_DIR = os.path.join(THIRD_PARTY_DIR,
  38. 'llvm-bootstrap-install')
  39. LLVM_INSTRUMENTED_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm-instrumented')
  40. LLVM_PROFDATA_FILE = os.path.join(LLVM_INSTRUMENTED_DIR, 'profdata.prof')
  41. CHROME_TOOLS_SHIM_DIR = os.path.join(LLVM_DIR, 'llvm', 'tools', 'chrometools')
  42. LLVM_BUILD_TOOLS_DIR = os.path.abspath(
  43. os.path.join(LLVM_DIR, '..', 'llvm-build-tools'))
  44. ANDROID_NDK_DIR = os.path.join(
  45. CHROMIUM_DIR, 'third_party', 'android_ndk')
  46. FUCHSIA_SDK_DIR = os.path.join(CHROMIUM_DIR, 'third_party', 'fuchsia-sdk',
  47. 'sdk')
  48.  
  49. BUG_REPORT_URL = ('https://crbug.com and run'
  50. ' tools/clang/scripts/process_crashreports.py'
  51. ' (only works inside Google) which will upload a report')
  52.  
  53.  
  54. win_sdk_dir = None
  55. def GetWinSDKDir():
  56. """Get the location of the current SDK."""
  57. global win_sdk_dir
  58. if win_sdk_dir:
  59. return win_sdk_dir
  60.  
  61. # Don't let vs_toolchain overwrite our environment.
  62. environ_bak = os.environ
  63.  
  64. sys.path.append(os.path.join(CHROMIUM_DIR, 'build'))
  65. import vs_toolchain
  66. win_sdk_dir = vs_toolchain.SetEnvironmentAndGetSDKDir()
  67. msvs_version = vs_toolchain.GetVisualStudioVersion()
  68.  
  69. if bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1'))):
  70. dia_path = os.path.join(win_sdk_dir, '..', 'DIA SDK', 'bin', 'amd64')
  71. else:
  72. if 'GYP_MSVS_OVERRIDE_PATH' not in os.environ:
  73. vs_path = vs_toolchain.DetectVisualStudioPath()
  74. else:
  75. vs_path = os.environ['GYP_MSVS_OVERRIDE_PATH']
  76. dia_path = os.path.join(vs_path, 'DIA SDK', 'bin', 'amd64')
  77.  
  78. os.environ = environ_bak
  79. return win_sdk_dir
  80.  
  81.  
  82. def RunCommand(command, msvc_arch=None, env=None, fail_hard=True):
  83. """Run command and return success (True) or failure; or if fail_hard is
  84. True, exit on failure. If msvc_arch is set, runs the command in a
  85. shell with the msvc tools for that architecture."""
  86.  
  87. if msvc_arch and sys.platform == 'win32':
  88. command = command
  89.  
  90. # https://docs.python.org/2/library/subprocess.html:
  91. # "On Unix with shell=True [...] if args is a sequence, the first item
  92. # specifies the command string, and any additional items will be treated as
  93. # additional arguments to the shell itself. That is to say, Popen does the
  94. # equivalent of:
  95. # Popen(['/bin/sh', '-c', args[0], args[1], ...])"
  96. #
  97. # We want to pass additional arguments to command[0], not to the shell,
  98. # so manually join everything into a single string.
  99. # Annoyingly, for "svn co url c:\path", pipes.quote() thinks that it should
  100. # quote c:\path but svn can't handle quoted paths on Windows. Since on
  101. # Windows follow-on args are passed to args[0] instead of the shell, don't
  102. # do the single-string transformation there.
  103. if sys.platform != 'win32':
  104. command = ' '.join([pipes.quote(c) for c in command])
  105. print('Running', command)
  106. if subprocess.call(command, env=env, shell=True) == 0:
  107. return True
  108. print('Failed.')
  109. if fail_hard:
  110. sys.exit(1)
  111. return False
  112.  
  113.  
  114. def CopyFile(src, dst):
  115. """Copy a file from src to dst."""
  116. print("Copying %s to %s" % (src, dst))
  117. shutil.copy(src, dst)
  118.  
  119.  
  120. def CopyDirectoryContents(src, dst):
  121. """Copy the files from directory src to dst."""
  122. dst = os.path.realpath(dst) # realpath() in case dst ends in /..
  123. EnsureDirExists(dst)
  124. for f in os.listdir(src):
  125. CopyFile(os.path.join(src, f), dst)
  126.  
  127.  
  128. def CheckoutLLVM(commit, dir):
  129. """Checkout the LLVM monorepo at a certain git commit in dir. Any local
  130. modifications in dir will be lost."""
  131.  
  132. print('Checking out LLVM monorepo %s into %s' % (commit, dir))
  133.  
  134. # Try updating the current repo if it exists and has no local diff.
  135. if os.path.isdir(dir):
  136. os.chdir(dir)
  137. # git diff-index --quiet returns success when there is no diff.
  138. # Also check that the first commit is reachable.
  139. if (RunCommand(['git', 'diff-index', '--quiet', 'HEAD'], fail_hard=False)
  140. and RunCommand(['git', 'fetch'], fail_hard=False)
  141. and RunCommand(['git', 'checkout', commit], fail_hard=False)):
  142. return
  143.  
  144. # If we can't use the current repo, delete it.
  145. os.chdir(CHROMIUM_DIR) # Can't remove dir if we're in it.
  146. print('Removing %s.' % dir)
  147. RmTree(dir)
  148.  
  149. clone_cmd = ['git', 'clone', 'https://github.com/llvm/llvm-project/', dir]
  150.  
  151. if RunCommand(clone_cmd, fail_hard=False):
  152. os.chdir(dir)
  153. if RunCommand(['git', 'checkout', commit], fail_hard=False):
  154. return
  155.  
  156. print('CheckoutLLVM failed.')
  157. sys.exit(1)
  158.  
  159.  
  160. def UrlOpen(url):
  161. # TODO(crbug.com/1067752): Use urllib once certificates are fixed.
  162. return subprocess.check_output(['curl', '--silent', url],
  163. universal_newlines=True)
  164.  
  165.  
  166. def GetLatestLLVMCommit():
  167. """Get the latest commit hash in the LLVM monorepo."""
  168. ref = json.loads(
  169. UrlOpen(('https://api.github.com/repos/'
  170. 'llvm/llvm-project/git/refs/heads/main')))
  171. assert ref['object']['type'] == 'commit'
  172. return ref['object']['sha']
  173.  
  174.  
  175. def GetCommitDescription(commit):
  176. """Get the output of `git describe`.
  177.  
  178. Needs to be called from inside the git repository dir."""
  179. git_exe = 'git.bat' if sys.platform.startswith('win') else 'git'
  180. return subprocess.check_output(
  181. [git_exe, 'describe', '--long', '--abbrev=8', commit],
  182. universal_newlines=True).rstrip()
  183.  
  184.  
  185. def DeleteChromeToolsShim():
  186. OLD_SHIM_DIR = os.path.join(LLVM_DIR, 'tools', 'zzz-chrometools')
  187. shutil.rmtree(OLD_SHIM_DIR, ignore_errors=True)
  188. shutil.rmtree(CHROME_TOOLS_SHIM_DIR, ignore_errors=True)
  189.  
  190.  
  191. def CreateChromeToolsShim():
  192. """Hooks the Chrome tools into the LLVM build.
  193.  
  194. Several Chrome tools have dependencies on LLVM/Clang libraries. The LLVM build
  195. detects implicit tools in the tools subdirectory, so this helper install a
  196. shim CMakeLists.txt that forwards to the real directory for the Chrome tools.
  197.  
  198. Note that the shim directory name intentionally has no - or _. The implicit
  199. tool detection logic munges them in a weird way."""
  200. assert not any(i in os.path.basename(CHROME_TOOLS_SHIM_DIR) for i in '-_')
  201. os.mkdir(CHROME_TOOLS_SHIM_DIR)
  202. with open(os.path.join(CHROME_TOOLS_SHIM_DIR, 'CMakeLists.txt'), 'w') as f:
  203. f.write('# Automatically generated by tools/clang/scripts/update.py. ' +
  204. 'Do not edit.\n')
  205. f.write('# Since tools/clang is located in another directory, use the \n')
  206. f.write('# two arg version to specify where build artifacts go. CMake\n')
  207. f.write('# disallows reuse of the same binary dir for multiple source\n')
  208. f.write('# dirs, so the build artifacts need to go into a subdirectory.\n')
  209. f.write('if (CHROMIUM_TOOLS_SRC)\n')
  210. f.write(' add_subdirectory(${CHROMIUM_TOOLS_SRC} ' +
  211. '${CMAKE_CURRENT_BINARY_DIR}/a)\n')
  212. f.write('endif (CHROMIUM_TOOLS_SRC)\n')
  213.  
  214.  
  215. def AddCMakeToPath(args):
  216. """Download CMake and add it to PATH."""
  217. if args.use_system_cmake:
  218. return
  219.  
  220. if sys.platform == 'win32':
  221. zip_name = 'cmake-3.17.1-win64-x64.zip'
  222. dir_name = ['cmake-3.17.1-win64-x64', 'bin']
  223. elif sys.platform == 'darwin':
  224. if platform.machine() == 'arm64':
  225. # TODO(thakis): Move to 3.20 everywhere.
  226. zip_name = 'cmake-3.20.0-macos-universal.tar.gz'
  227. dir_name = [
  228. 'cmake-3.20.0-macos-universal', 'CMake.app', 'Contents', 'bin'
  229. ]
  230. else:
  231. zip_name = 'cmake-3.17.1-Darwin-x86_64.tar.gz'
  232. dir_name = ['cmake-3.17.1-Darwin-x86_64', 'CMake.app', 'Contents', 'bin']
  233. else:
  234. zip_name = 'cmake-3.17.1-Linux-x86_64.tar.gz'
  235. dir_name = ['cmake-3.17.1-Linux-x86_64', 'bin']
  236.  
  237. cmake_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, *dir_name)
  238. if not os.path.exists(cmake_dir):
  239. DownloadAndUnpack(CDS_URL + '/tools/' + zip_name, LLVM_BUILD_TOOLS_DIR)
  240. os.environ['PATH'] = cmake_dir + os.pathsep + os.environ.get('PATH', '')
  241.  
  242.  
  243. def AddGnuWinToPath():
  244. """Download some GNU win tools and add them to PATH."""
  245. if sys.platform != 'win32':
  246. return
  247.  
  248. gnuwin_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, 'gnuwin')
  249. GNUWIN_VERSION = '14'
  250. GNUWIN_STAMP = os.path.join(gnuwin_dir, 'stamp')
  251. if ReadStampFile(GNUWIN_STAMP) == GNUWIN_VERSION:
  252. print('GNU Win tools already up to date.')
  253. else:
  254. zip_name = 'gnuwin-%s.zip' % GNUWIN_VERSION
  255. DownloadAndUnpack(CDS_URL + '/tools/' + zip_name, LLVM_BUILD_TOOLS_DIR)
  256. WriteStampFile(GNUWIN_VERSION, GNUWIN_STAMP)
  257.  
  258. os.environ['PATH'] = gnuwin_dir + os.pathsep + os.environ.get('PATH', '')
  259.  
  260. # find.exe, mv.exe and rm.exe are from MSYS (see crrev.com/389632). MSYS uses
  261. # Cygwin under the hood, and initializing Cygwin has a race-condition when
  262. # getting group and user data from the Active Directory is slow. To work
  263. # around this, use a horrible hack telling it not to do that.
  264. # See https://crbug.com/905289
  265. etc = os.path.join(gnuwin_dir, '..', '..', 'etc')
  266. EnsureDirExists(etc)
  267. with open(os.path.join(etc, 'nsswitch.conf'), 'w') as f:
  268. f.write('passwd: files\n')
  269. f.write('group: files\n')
  270.  
  271.  
  272. def AddZlibToPath():
  273. """Download and build zlib, and add to PATH."""
  274. zlib_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, 'zlib-1.2.11')
  275. if os.path.exists(zlib_dir):
  276. RmTree(zlib_dir)
  277. zip_name = 'zlib-1.2.11.tar.gz'
  278. DownloadAndUnpack(CDS_URL + '/tools/' + zip_name, LLVM_BUILD_TOOLS_DIR)
  279. os.chdir(zlib_dir)
  280. zlib_files = [
  281. 'adler32', 'compress', 'crc32', 'deflate', 'gzclose', 'gzlib', 'gzread',
  282. 'gzwrite', 'inflate', 'infback', 'inftrees', 'inffast', 'trees',
  283. 'uncompr', 'zutil'
  284. ]
  285. cl_flags = [
  286. '/nologo', '/O2', '/DZLIB_DLL', '/c', '/D_CRT_SECURE_NO_DEPRECATE',
  287. '/D_CRT_NONSTDC_NO_DEPRECATE'
  288. ]
  289. RunCommand(
  290. ['cl.exe'] + [f + '.c' for f in zlib_files] + cl_flags, msvc_arch='x64')
  291. RunCommand(
  292. ['lib.exe'] + [f + '.obj'
  293. for f in zlib_files] + ['/nologo', '/out:zlib.lib'],
  294. msvc_arch='x64')
  295. # Remove the test directory so it isn't found when trying to find
  296. # test.exe.
  297. shutil.rmtree('test')
  298.  
  299. os.environ['PATH'] = zlib_dir + os.pathsep + os.environ.get('PATH', '')
  300. return zlib_dir
  301.  
  302.  
  303. def DownloadRPMalloc():
  304. """Download rpmalloc."""
  305. rpmalloc_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, 'rpmalloc')
  306. if os.path.exists(rpmalloc_dir):
  307. RmTree(rpmalloc_dir)
  308.  
  309. # Using rpmalloc bc1923f rather than the latest release (1.4.1) because
  310. # it contains the fix for https://github.com/mjansson/rpmalloc/pull/186
  311. # which would cause lld to deadlock.
  312. # The zip file was created and uploaded as follows:
  313. # $ mkdir rpmalloc
  314. # $ curl -L https://github.com/mjansson/rpmalloc/archive/bc1923f436539327707b08ef9751a7a87bdd9d2f.tar.gz \
  315. # | tar -C rpmalloc --strip-components=1 -xzf -
  316. # $ GZIP=-9 tar vzcf rpmalloc-bc1923f.tgz rpmalloc
  317. # $ gsutil.py cp -n -a public-read rpmalloc-bc1923f.tgz \
  318. # gs://chromium-browser-clang/tools/
  319. zip_name = 'rpmalloc-bc1923f.tgz'
  320. DownloadAndUnpack(CDS_URL + '/tools/' + zip_name, LLVM_BUILD_TOOLS_DIR)
  321. rpmalloc_dir = rpmalloc_dir.replace('\\', '/')
  322. return rpmalloc_dir
  323.  
  324.  
  325. def MaybeDownloadHostGcc(args):
  326. """Download a modern GCC host compiler on Linux."""
  327. if not sys.platform.startswith('linux') or args.gcc_toolchain:
  328. return
  329. gcc_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, 'gcc-10.2.0-trusty')
  330. if not os.path.exists(gcc_dir):
  331. DownloadAndUnpack(CDS_URL + '/tools/gcc-10.2.0-trusty.tgz', gcc_dir)
  332. args.gcc_toolchain = gcc_dir
  333.  
  334.  
  335. def VerifyVersionOfBuiltClangMatchesVERSION():
  336. """Checks that `clang --version` outputs RELEASE_VERSION. If this
  337. fails, update.RELEASE_VERSION is out-of-date and needs to be updated (possibly
  338. in an `if args.llvm_force_head_revision:` block inupdate. main() first)."""
  339. clang = os.path.join(LLVM_BUILD_DIR, 'bin', 'clang')
  340. if sys.platform == 'win32':
  341. clang += '-cl.exe'
  342. version_out = subprocess.check_output([clang, '--version'],
  343. universal_newlines=True)
  344. version_out = re.match(r'clang version ([0-9.]+)', version_out).group(1)
  345. if version_out != RELEASE_VERSION:
  346. print(('unexpected clang version %s (not %s), '
  347. 'update RELEASE_VERSION in update.py')
  348. % (version_out, RELEASE_VERSION))
  349. sys.exit(1)
  350.  
  351.  
  352. def VerifyZlibSupport():
  353. """Check that clang was built with zlib support enabled."""
  354. clang = os.path.join(LLVM_BUILD_DIR, 'bin', 'clang')
  355. test_file = '/dev/null'
  356. if sys.platform == 'win32':
  357. clang += '.exe'
  358. test_file = 'nul'
  359.  
  360. print('Checking for zlib support')
  361. clang_out = subprocess.check_output([
  362. clang, '-target', 'x86_64-unknown-linux-gnu', '-gz', '-c', '-###', '-x',
  363. 'c', test_file
  364. ],
  365. stderr=subprocess.STDOUT,
  366. universal_newlines=True)
  367. if (re.search(r'--compress-debug-sections', clang_out)):
  368. print('OK')
  369. else:
  370. print(('Failed to detect zlib support!\n\n(driver output: %s)') % clang_out)
  371. sys.exit(1)
  372.  
  373.  
  374. def CopyLibstdcpp(args, build_dir):
  375. if not args.gcc_toolchain:
  376. return
  377. # Find libstdc++.so.6
  378. libstdcpp = subprocess.check_output([
  379. os.path.join(args.gcc_toolchain, 'bin', 'g++'),
  380. '-print-file-name=libstdc++.so.6'
  381. ],
  382. universal_newlines=True).rstrip()
  383.  
  384. # Copy libstdc++.so.6 into the build dir so that the built binaries can find
  385. # it. Binaries get their rpath set to $origin/../lib/. For clang, lld,
  386. # etc. that live in the bin/ directory, this means they expect to find the .so
  387. # in their neighbouring lib/ dir.
  388. # For unit tests we pass -Wl,-rpath to the linker pointing to the lib64 dir
  389. # in the gcc toolchain, via LLVM_LOCAL_RPATH below.
  390. # The two fuzzer tests are weird in that they copy the fuzzer binary from bin/
  391. # into the test tree under a different name. To make the relative rpath in
  392. # them work, copy libstdc++ to the copied location for now.
  393. # There is also a compiler-rt test that copies llvm-symbolizer out of bin/.
  394. # TODO(thakis): Instead, make the upstream lit.local.cfg.py for these 2 tests
  395. # check if the binary contains an rpath and if so disable the tests.
  396. for d in ['lib',
  397. 'test/tools/llvm-isel-fuzzer/lib',
  398. 'test/tools/llvm-opt-fuzzer/lib']:
  399. EnsureDirExists(os.path.join(build_dir, d))
  400. CopyFile(libstdcpp, os.path.join(build_dir, d))
  401.  
  402. sanitizer_common_tests = os.path.join(build_dir,
  403. 'projects/compiler-rt/test/sanitizer_common')
  404. if os.path.exists(sanitizer_common_tests):
  405. for d in ['asan-i386-Linux', 'asan-x86_64-Linux', 'lsan-i386-Linux',
  406. 'lsan-x86_64-Linux', 'msan-x86_64-Linux', 'tsan-x86_64-Linux',
  407. 'ubsan-i386-Linux', 'ubsan-x86_64-Linux']:
  408. libpath = os.path.join(sanitizer_common_tests, d, 'Output', 'lib')
  409. EnsureDirExists(libpath)
  410. CopyFile(libstdcpp, libpath)
  411.  
  412.  
  413. def gn_arg(v):
  414. if v == 'True':
  415. return True
  416. if v == 'False':
  417. return False
  418. raise argparse.ArgumentTypeError('Expected one of %r or %r' % (
  419. 'True', 'False'))
  420.  
  421.  
  422. def main():
  423. parser = argparse.ArgumentParser(description='Build Clang.')
  424. parser.add_argument('--bootstrap', action='store_true',
  425. help='first build clang with CC, then with itself.')
  426. parser.add_argument('--build-mac-arm', action='store_true',
  427. help='Build arm binaries. Only valid on macOS.')
  428. parser.add_argument('--disable-asserts', action='store_true',
  429. help='build with asserts disabled')
  430. parser.add_argument('--gcc-toolchain', help='what gcc toolchain to use for '
  431. 'building; --gcc-toolchain=/opt/foo picks '
  432. '/opt/foo/bin/gcc')
  433. parser.add_argument('--pgo', action='store_true', help='build with PGO')
  434. parser.add_argument('--thinlto',
  435. action='store_true',
  436. help='build with ThinLTO')
  437. parser.add_argument('--llvm-force-head-revision', action='store_true',
  438. help='build the latest revision')
  439. parser.add_argument('--run-tests', action='store_true',
  440. help='run tests after building')
  441. parser.add_argument('--skip-build', action='store_true',
  442. help='do not build anything')
  443. parser.add_argument('--skip-checkout', action='store_true',
  444. help='do not create or update any checkouts')
  445. parser.add_argument('--build-dir',
  446. help='Override build directory')
  447. parser.add_argument('--extra-tools', nargs='*', default=[],
  448. help='select additional chrome tools to build')
  449. parser.add_argument('--use-system-cmake', action='store_true',
  450. help='use the cmake from PATH instead of downloading '
  451. 'and using prebuilt cmake binaries')
  452. parser.add_argument('--with-android', type=gn_arg, nargs='?', const=True,
  453. help='build the Android ASan runtime (linux only)',
  454. default=sys.platform.startswith('linux'))
  455. parser.add_argument('--with-fuchsia',
  456. type=gn_arg,
  457. nargs='?',
  458. const=True,
  459. help='build the Fuchsia runtimes (linux and mac only)',
  460. default=sys.platform.startswith('linux')
  461. or sys.platform.startswith('darwin'))
  462. parser.add_argument('--without-android', action='store_false',
  463. help='don\'t build Android ASan runtime (linux only)',
  464. dest='with_android')
  465. parser.add_argument('--without-fuchsia', action='store_false',
  466. help='don\'t build Fuchsia clang_rt runtime (linux/mac)',
  467. dest='with_fuchsia',
  468. default=sys.platform in ('linux2', 'darwin'))
  469. args = parser.parse_args()
  470.  
  471. global CLANG_REVISION, PACKAGE_VERSION, LLVM_BUILD_DIR
  472.  
  473. if (args.pgo or args.thinlto) and not args.bootstrap:
  474. print('--pgo/--thinlto requires --bootstrap')
  475. return 1
  476. if args.with_android and not os.path.exists(ANDROID_NDK_DIR):
  477. print('Android NDK not found at ' + ANDROID_NDK_DIR)
  478. print('The Android NDK is needed to build a Clang whose -fsanitize=address')
  479. print('works on Android. See ')
  480. print('https://www.chromium.org/developers/how-tos/android-build-instructions')
  481. print('for how to install the NDK, or pass --without-android.')
  482. return 1
  483.  
  484. if args.with_fuchsia and not os.path.exists(FUCHSIA_SDK_DIR):
  485. print('Fuchsia SDK not found at ' + FUCHSIA_SDK_DIR)
  486. print('The Fuchsia SDK is needed to build libclang_rt for Fuchsia.')
  487. print('Install the Fuchsia SDK by adding fuchsia to the ')
  488. print('target_os section in your .gclient and running hooks, ')
  489. print('or pass --without-fuchsia.')
  490. print(
  491. 'https://chromium.googlesource.com/chromium/src/+/main/docs/fuchsia/build_instructions.md'
  492. )
  493. print('for general Fuchsia build instructions.')
  494. return 1
  495.  
  496. if args.build_mac_arm and sys.platform != 'darwin':
  497. print('--build-mac-arm only valid on macOS')
  498. return 1
  499. if args.build_mac_arm and platform.machine() == 'arm64':
  500. print('--build-mac-arm only valid on intel to cross-build arm')
  501. return 1
  502.  
  503. # Don't buffer stdout, so that print statements are immediately flushed.
  504. # LLVM tests print output without newlines, so with buffering they won't be
  505. # immediately printed.
  506. major, _, _, _, _ = sys.version_info
  507. if major == 3:
  508. # Python3 only allows unbuffered output for binary streams. This
  509. # workaround comes from https://stackoverflow.com/a/181654/4052492.
  510. sys.stdout = io.TextIOWrapper(open(sys.stdout.fileno(), 'wb', 0),
  511. write_through=True)
  512. else:
  513. sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
  514.  
  515. # The gnuwin package also includes curl, which is needed to interact with the
  516. # github API below.
  517. # TODO(crbug.com/1067752): Use urllib once certificates are fixed, and
  518. # move this down to where we fetch other build tools.
  519. AddGnuWinToPath()
  520.  
  521. # TODO(crbug.com/929645): Remove once we build on host systems with a modern
  522. # enough GCC to build Clang.
  523. MaybeDownloadHostGcc(args)
  524.  
  525. if sys.platform == 'darwin':
  526. isysroot = subprocess.check_output(['xcrun', '--show-sdk-path'],
  527. universal_newlines=True).rstrip()
  528.  
  529. if args.build_dir:
  530. LLVM_BUILD_DIR = args.build_dir
  531.  
  532. if args.llvm_force_head_revision:
  533. checkout_revision = GetLatestLLVMCommit()
  534. else:
  535. checkout_revision = CLANG_REVISION
  536.  
  537. if not args.skip_checkout:
  538. CheckoutLLVM(checkout_revision, LLVM_DIR)
  539.  
  540. if args.llvm_force_head_revision:
  541. CLANG_REVISION = GetCommitDescription(checkout_revision)
  542. PACKAGE_VERSION = '%s-0' % CLANG_REVISION
  543.  
  544. print('Locally building clang %s...' % PACKAGE_VERSION)
  545. WriteStampFile('', STAMP_FILE)
  546. WriteStampFile('', FORCE_HEAD_REVISION_FILE)
  547.  
  548. AddCMakeToPath(args)
  549. DeleteChromeToolsShim()
  550.  
  551.  
  552. if args.skip_build:
  553. return 0
  554.  
  555. # The variable "lld" is only used on Windows because only there does setting
  556. # CMAKE_LINKER have an effect: On Windows, the linker is called directly,
  557. # while elsewhere it's called through the compiler driver, and we pass
  558. # -fuse-ld=lld there to make the compiler driver call the linker (by setting
  559. # LLVM_ENABLE_LLD).
  560. cc, cxx, lld = None, None, None
  561.  
  562. cflags = []
  563. cxxflags = []
  564. ldflags = []
  565.  
  566. targets = 'X86'
  567.  
  568. projects = 'clang;compiler-rt;lld;polly'
  569.  
  570. if sys.platform == 'darwin':
  571. # clang needs libc++, else -stdlib=libc++ won't find includes
  572. # (this is needed for bootstrap builds and for building the fuchsia runtime)
  573. projects += ';libcxx'
  574.  
  575. base_cmake_args = [
  576. '-GNinja',
  577. '-DCMAKE_BUILD_TYPE=Release',
  578. '-DLLVM_ENABLE_ASSERTIONS=%s' % ('OFF' if args.disable_asserts else 'ON'),
  579. '-DLLVM_ENABLE_PROJECTS=' + projects,
  580. '-DLLVM_TARGETS_TO_BUILD=' + targets,
  581. '-DLLVM_ENABLE_PIC=ON',
  582. '-DLLVM_ENABLE_UNWIND_TABLES=OFF',
  583. '-DLLVM_ENABLE_TERMINFO=OFF',
  584. '-DLLVM_ENABLE_Z3_SOLVER=OFF',
  585. '-DCLANG_PLUGIN_SUPPORT=ON',
  586. '-DCLANG_ENABLE_STATIC_ANALYZER=OFF',
  587. '-DCLANG_ENABLE_ARCMT=OFF',
  588. '-DBUG_REPORT_URL=' + BUG_REPORT_URL,
  589. # Don't run Go bindings tests; PGO makes them confused.
  590. '-DLLVM_INCLUDE_GO_TESTS=OFF',
  591. # TODO(crbug.com/1113475): Update binutils.
  592. '-DENABLE_X86_RELAX_RELOCATIONS=NO',
  593. # See crbug.com/1126219: Use native symbolizer instead of DIA
  594. '-DLLVM_ENABLE_DIA_SDK=OFF',
  595. # See crbug.com/1205046: don't build scudo (and others we don't need).
  596. '-DCOMPILER_RT_SANITIZERS_TO_BUILD=asan;dfsan;msan;hwasan;tsan;cfi',
  597. ]
  598.  
  599. if args.gcc_toolchain:
  600. # Use the specified gcc installation for building.
  601. cc = os.path.join(args.gcc_toolchain, 'bin', 'gcc')
  602. cxx = os.path.join(args.gcc_toolchain, 'bin', 'g++')
  603. if not os.access(cc, os.X_OK):
  604. print('Invalid --gcc-toolchain: ' + args.gcc_toolchain)
  605. return 1
  606. base_cmake_args += [
  607. '-DLLVM_LOCAL_RPATH=' + os.path.join(args.gcc_toolchain, 'lib64')
  608. ]
  609.  
  610. if sys.platform == 'darwin':
  611. # For libc++, we only want the headers.
  612. base_cmake_args.extend([
  613. '-DLIBCXX_ENABLE_SHARED=OFF',
  614. '-DLIBCXX_ENABLE_STATIC=OFF',
  615. '-DLIBCXX_INCLUDE_TESTS=OFF',
  616. '-DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=OFF',
  617. ])
  618.  
  619. if args.gcc_toolchain:
  620. # Force compiler-rt tests to use our gcc toolchain (including libstdc++.so)
  621. # because the one on the host may be too old.
  622. base_cmake_args.append(
  623. '-DCOMPILER_RT_TEST_COMPILER_CFLAGS=--gcc-toolchain=' +
  624. args.gcc_toolchain + ' -Wl,-rpath,' +
  625. os.path.join(args.gcc_toolchain, 'lib64') + ' -Wl,-rpath,' +
  626. os.path.join(args.gcc_toolchain, 'lib32'))
  627.  
  628. if sys.platform == 'win32':
  629. base_cmake_args.append('-DLLVM_USE_CRT_RELEASE=MT')
  630.  
  631. # Require zlib compression.
  632. zlib_dir = AddZlibToPath()
  633. cflags.append('-I' + zlib_dir)
  634. cxxflags.append('-I' + zlib_dir)
  635. ldflags.append('-LIBPATH:' + zlib_dir)
  636.  
  637. # Use rpmalloc. For faster ThinLTO linking.
  638. rpmalloc_dir = DownloadRPMalloc()
  639. base_cmake_args.append('-DLLVM_INTEGRATED_CRT_ALLOC=' + rpmalloc_dir)
  640.  
  641. if sys.platform != 'win32':
  642. # libxml2 is required by the Win manifest merging tool used in cross-builds.
  643. base_cmake_args.append('-DLLVM_ENABLE_LIBXML2=FORCE_ON')
  644.  
  645. if args.bootstrap:
  646. print('Building bootstrap compiler')
  647. if os.path.exists(LLVM_BOOTSTRAP_DIR):
  648. RmTree(LLVM_BOOTSTRAP_DIR)
  649. EnsureDirExists(LLVM_BOOTSTRAP_DIR)
  650. os.chdir(LLVM_BOOTSTRAP_DIR)
  651.  
  652. projects = 'clang'
  653. if args.pgo:
  654. # Need libclang_rt.profile
  655. projects += ';compiler-rt'
  656. if sys.platform != 'darwin':
  657. projects += ';lld'
  658. if sys.platform == 'darwin':
  659. # Need libc++ and compiler-rt for the bootstrap compiler on mac.
  660. projects += ';libcxx;compiler-rt'
  661.  
  662. bootstrap_targets = 'X86'
  663. if sys.platform == 'darwin':
  664. # Need ARM and AArch64 for building the ios clang_rt.
  665. bootstrap_targets += ';ARM;AArch64'
  666. bootstrap_args = base_cmake_args + [
  667. '-DLLVM_TARGETS_TO_BUILD=' + bootstrap_targets,
  668. '-DLLVM_ENABLE_PROJECTS=' + projects,
  669. '-DCMAKE_INSTALL_PREFIX=' + LLVM_BOOTSTRAP_INSTALL_DIR,
  670. '-DCMAKE_C_FLAGS=' + ' '.join(cflags),
  671. '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags),
  672. '-DCMAKE_EXE_LINKER_FLAGS=' + ' '.join(ldflags),
  673. '-DCMAKE_SHARED_LINKER_FLAGS=' + ' '.join(ldflags),
  674. '-DCMAKE_MODULE_LINKER_FLAGS=' + ' '.join(ldflags),
  675. # Ignore args.disable_asserts for the bootstrap compiler.
  676. '-DLLVM_ENABLE_ASSERTIONS=ON',
  677. ]
  678. if sys.platform == 'darwin':
  679. # On macOS, the bootstrap toolchain needs to have compiler-rt because
  680. # dsymutil's link needs libclang_rt.osx.a. Only the x86_64 osx
  681. # libraries are needed though, and only libclang_rt (i.e.
  682. # COMPILER_RT_BUILD_BUILTINS).
  683. bootstrap_args.extend([
  684. '-DCOMPILER_RT_BUILD_BUILTINS=ON',
  685. '-DCOMPILER_RT_BUILD_CRT=OFF',
  686. '-DCOMPILER_RT_BUILD_LIBFUZZER=OFF',
  687. '-DCOMPILER_RT_BUILD_MEMPROF=OFF',
  688. '-DCOMPILER_RT_BUILD_ORC=OFF',
  689. '-DCOMPILER_RT_BUILD_SANITIZERS=OFF',
  690. '-DCOMPILER_RT_BUILD_XRAY=OFF',
  691. '-DCOMPILER_RT_ENABLE_IOS=OFF',
  692. '-DCOMPILER_RT_ENABLE_WATCHOS=OFF',
  693. '-DCOMPILER_RT_ENABLE_TVOS=OFF',
  694. ])
  695. if platform.machine() == 'arm64':
  696. bootstrap_args.extend(['-DDARWIN_osx_ARCHS=arm64'])
  697. else:
  698. bootstrap_args.extend(['-DDARWIN_osx_ARCHS=x86_64'])
  699. elif args.pgo:
  700. # PGO needs libclang_rt.profile but none of the other compiler-rt stuff.
  701. bootstrap_args.extend([
  702. '-DCOMPILER_RT_BUILD_BUILTINS=OFF',
  703. '-DCOMPILER_RT_BUILD_CRT=OFF',
  704. '-DCOMPILER_RT_BUILD_LIBFUZZER=OFF',
  705. '-DCOMPILER_RT_BUILD_MEMPROF=OFF',
  706. '-DCOMPILER_RT_BUILD_ORC=OFF',
  707. '-DCOMPILER_RT_BUILD_PROFILE=ON',
  708. '-DCOMPILER_RT_BUILD_SANITIZERS=OFF',
  709. '-DCOMPILER_RT_BUILD_XRAY=OFF',
  710. ])
  711.  
  712. if cc is not None: bootstrap_args.append('-DCMAKE_C_COMPILER=' + cc)
  713. if cxx is not None: bootstrap_args.append('-DCMAKE_CXX_COMPILER=' + cxx)
  714. if lld is not None: bootstrap_args.append('-DCMAKE_LINKER=' + lld)
  715. RunCommand(['cmake'] + bootstrap_args + [os.path.join(LLVM_DIR, 'llvm')],
  716. msvc_arch='x64')
  717. CopyLibstdcpp(args, LLVM_BOOTSTRAP_DIR)
  718. CopyLibstdcpp(args, LLVM_BOOTSTRAP_INSTALL_DIR)
  719. RunCommand(['ninja'], msvc_arch='x64')
  720. if args.run_tests:
  721. test_targets = ['check-all']
  722. if sys.platform == 'darwin' and platform.machine() == 'arm64':
  723. # TODO(llvm.org/PR49918): Run check-all on mac/arm too.
  724. test_targets = ['check-llvm', 'check-clang']
  725. RunCommand(['ninja'] + test_targets, msvc_arch='x64')
  726. RunCommand(['ninja', 'install'], msvc_arch='x64')
  727.  
  728. if sys.platform == 'win32':
  729. cc = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang-cl.exe')
  730. cxx = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang-cl.exe')
  731. lld = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'lld-link.exe')
  732. # CMake has a hard time with backslashes in compiler paths:
  733. # https://stackoverflow.com/questions/13050827
  734. cc = cc.replace('\\', '/')
  735. cxx = cxx.replace('\\', '/')
  736. lld = lld.replace('\\', '/')
  737. else:
  738. cc = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang')
  739. cxx = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang++')
  740. if sys.platform.startswith('linux'):
  741. base_cmake_args.append('-DLLVM_ENABLE_LLD=ON')
  742.  
  743. if args.gcc_toolchain:
  744. # Tell the bootstrap compiler where to find the standard library headers
  745. # and shared object files.
  746. cflags.append('--gcc-toolchain=' + args.gcc_toolchain)
  747. cxxflags.append('--gcc-toolchain=' + args.gcc_toolchain)
  748.  
  749. print('Bootstrap compiler installed.')
  750.  
  751. if args.pgo:
  752. print('Building instrumented compiler')
  753. if os.path.exists(LLVM_INSTRUMENTED_DIR):
  754. RmTree(LLVM_INSTRUMENTED_DIR)
  755. EnsureDirExists(LLVM_INSTRUMENTED_DIR)
  756. os.chdir(LLVM_INSTRUMENTED_DIR)
  757.  
  758. projects = 'clang'
  759. if sys.platform == 'darwin':
  760. projects += ';libcxx;compiler-rt'
  761.  
  762. instrument_args = base_cmake_args + [
  763. '-DLLVM_ENABLE_PROJECTS=' + projects,
  764. '-DCMAKE_C_FLAGS=' + ' '.join(cflags),
  765. '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags),
  766. '-DCMAKE_EXE_LINKER_FLAGS=' + ' '.join(ldflags),
  767. '-DCMAKE_SHARED_LINKER_FLAGS=' + ' '.join(ldflags),
  768. '-DCMAKE_MODULE_LINKER_FLAGS=' + ' '.join(ldflags),
  769. # Build with instrumentation.
  770. '-DLLVM_BUILD_INSTRUMENTED=IR',
  771. ]
  772. # Build with the bootstrap compiler.
  773. if cc is not None: instrument_args.append('-DCMAKE_C_COMPILER=' + cc)
  774. if cxx is not None: instrument_args.append('-DCMAKE_CXX_COMPILER=' + cxx)
  775. if lld is not None: instrument_args.append('-DCMAKE_LINKER=' + lld)
  776.  
  777. RunCommand(['cmake'] + instrument_args + [os.path.join(LLVM_DIR, 'llvm')],
  778. msvc_arch='x64')
  779. CopyLibstdcpp(args, LLVM_INSTRUMENTED_DIR)
  780. RunCommand(['ninja'], msvc_arch='x64')
  781. print('Instrumented compiler built.')
  782.  
  783. # Train by building some C++ code.
  784. #
  785. # pgo_training-1.ii is a preprocessed (on Linux) version of
  786. # src/third_party/blink/renderer/core/layout/layout_object.cc, selected
  787. # because it's a large translation unit in Blink, which is normally the
  788. # slowest part of Chromium to compile. Using this, we get ~20% shorter
  789. # build times for Linux, Android, and Mac, which is also what we got when
  790. # training by actually building a target in Chromium. (For comparison, a
  791. # C++-y "Hello World" program only resulted in 14% faster builds.)
  792. # See https://crbug.com/966403#c16 for all numbers.
  793. #
  794. # Although the training currently only exercises Clang, it does involve LLVM
  795. # internals, and so LLD also benefits when used for ThinLTO links.
  796. #
  797. # NOTE: Tidy uses binaries built with this profile, but doesn't seem to
  798. # gain much from it. If tidy's execution time becomes a concern, it might
  799. # be good to investigate that.
  800. #
  801. # TODO(hans): Enhance the training, perhaps by including preprocessed code
  802. # from more platforms, and by doing some linking so that lld can benefit
  803. # from PGO as well. Perhaps the training could be done asynchronously by
  804. # dedicated buildbots that upload profiles to the cloud.
  805. training_source = 'pgo_training-1.ii'
  806. with open(training_source, 'wb') as f:
  807. DownloadUrl(CDS_URL + '/' + training_source, f)
  808. train_cmd = [os.path.join(LLVM_INSTRUMENTED_DIR, 'bin', 'clang++'),
  809. '-target', 'x86_64-unknown-unknown', '-O2', '-g', '-std=c++14',
  810. '-fno-exceptions', '-fno-rtti', '-w', '-c', training_source]
  811. if sys.platform == 'darwin':
  812. train_cmd.extend(['-stdlib=libc++', '-isysroot', isysroot])
  813. RunCommand(train_cmd, msvc_arch='x64')
  814.  
  815. # Merge profiles.
  816. profdata = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'llvm-profdata')
  817. RunCommand([profdata, 'merge', '-output=' + LLVM_PROFDATA_FILE] +
  818. glob.glob(os.path.join(LLVM_INSTRUMENTED_DIR, 'profiles',
  819. '*.profraw')), msvc_arch='x64')
  820. print('Profile generated.')
  821.  
  822. compiler_rt_args = [
  823. '-DCOMPILER_RT_BUILD_CRT=OFF',
  824. '-DCOMPILER_RT_BUILD_LIBFUZZER=OFF',
  825. '-DCOMPILER_RT_BUILD_MEMPROF=OFF',
  826. '-DCOMPILER_RT_BUILD_ORC=OFF',
  827. '-DCOMPILER_RT_BUILD_PROFILE=ON',
  828. '-DCOMPILER_RT_BUILD_SANITIZERS=ON',
  829. '-DCOMPILER_RT_BUILD_XRAY=OFF',
  830. ]
  831. if sys.platform == 'darwin':
  832. compiler_rt_args.extend([
  833. '-DCOMPILER_RT_BUILD_BUILTINS=ON',
  834. '-DCOMPILER_RT_ENABLE_IOS=ON',
  835. '-DCOMPILER_RT_ENABLE_WATCHOS=OFF',
  836. '-DCOMPILER_RT_ENABLE_TVOS=OFF',
  837. # armv7 is A5 and earlier, armv7s is A6+ (2012 and later, before 64-bit
  838. # iPhones). armv7k is Apple Watch, which we don't need.
  839. '-DDARWIN_ios_ARCHS=armv7;armv7s;arm64',
  840. '-DDARWIN_iossim_ARCHS=i386;x86_64;arm64',
  841. # We don't need 32-bit intel support for macOS, we only ship 64-bit.
  842. '-DDARWIN_osx_ARCHS=arm64;x86_64',
  843. ])
  844. else:
  845. compiler_rt_args.append('-DCOMPILER_RT_BUILD_BUILTINS=OFF')
  846.  
  847. # LLVM uses C++11 starting in llvm 3.5. On Linux, this means libstdc++4.7+ is
  848. # needed, on OS X it requires libc++. clang only automatically links to libc++
  849. # when targeting OS X 10.9+, so add stdlib=libc++ explicitly so clang can run
  850. # on OS X versions as old as 10.7.
  851. deployment_target = ''
  852.  
  853. if sys.platform == 'darwin' and args.bootstrap:
  854. # When building on 10.9, /usr/include usually doesn't exist, and while
  855. # Xcode's clang automatically sets a sysroot, self-built clangs don't.
  856. cflags = ['-isysroot', isysroot]
  857. cxxflags = ['-stdlib=libc++'] + cflags
  858. ldflags += ['-stdlib=libc++']
  859. deployment_target = '10.7'
  860.  
  861. # If building at head, define a macro that plugins can use for #ifdefing
  862. # out code that builds at head, but not at CLANG_REVISION or vice versa.
  863. if args.llvm_force_head_revision:
  864. cflags += ['-DLLVM_FORCE_HEAD_REVISION']
  865. cxxflags += ['-DLLVM_FORCE_HEAD_REVISION']
  866.  
  867. # Build PDBs for archival on Windows. Don't use RelWithDebInfo since it
  868. # has different optimization defaults than Release.
  869. # Also disable stack cookies (/GS-) for performance.
  870. if sys.platform == 'win32':
  871. cflags += ['/GS-']
  872. cxxflags += ['/GS-']
  873. ldflags += ['/DEBUG', '/OPT:REF', '/OPT:ICF']
  874.  
  875. deployment_env = None
  876. if deployment_target:
  877. deployment_env = os.environ.copy()
  878. deployment_env['MACOSX_DEPLOYMENT_TARGET'] = deployment_target
  879.  
  880. print('Building final compiler.')
  881.  
  882. default_tools = []
  883. chrome_tools = list(set(default_tools + args.extra_tools))
  884. if cc is not None: base_cmake_args.append('-DCMAKE_C_COMPILER=' + cc)
  885. if cxx is not None: base_cmake_args.append('-DCMAKE_CXX_COMPILER=' + cxx)
  886. if lld is not None: base_cmake_args.append('-DCMAKE_LINKER=' + lld)
  887. cmake_args = base_cmake_args + compiler_rt_args + [
  888. '-DCMAKE_C_FLAGS=' + ' '.join(cflags),
  889. '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags),
  890. '-DCMAKE_EXE_LINKER_FLAGS=' + ' '.join(ldflags),
  891. '-DCMAKE_SHARED_LINKER_FLAGS=' + ' '.join(ldflags),
  892. '-DCMAKE_MODULE_LINKER_FLAGS=' + ' '.join(ldflags),
  893. '-DCMAKE_INSTALL_PREFIX=' + LLVM_BUILD_DIR,
  894. '-DCHROMIUM_TOOLS_SRC=%s' % os.path.join(CHROMIUM_DIR, 'tools', 'clang'),
  895. '-DCHROMIUM_TOOLS=%s' % ';'.join(chrome_tools)]
  896. if args.pgo:
  897. cmake_args.append('-DLLVM_PROFDATA_FILE=' + LLVM_PROFDATA_FILE)
  898. if args.thinlto:
  899. cmake_args.append('-DLLVM_ENABLE_LTO=Thin')
  900. if sys.platform == 'win32':
  901. cmake_args.append('-DLLVM_ENABLE_ZLIB=FORCE_ON')
  902.  
  903. if sys.platform == 'darwin':
  904. cmake_args += ['-DCOMPILER_RT_ENABLE_IOS=ON',
  905. '-DSANITIZER_MIN_OSX_VERSION=10.7']
  906. if args.build_mac_arm:
  907. assert platform.machine() != 'arm64', 'build_mac_arm for cross build only'
  908. cmake_args += ['-DCMAKE_OSX_ARCHITECTURES=arm64',
  909. '-DLLVM_USE_HOST_TOOLS=ON']
  910.  
  911. # The default LLVM_DEFAULT_TARGET_TRIPLE depends on the host machine.
  912. # Set it explicitly to make the build of clang more hermetic, and also to
  913. # set it to arm64 when cross-building clang for mac/arm.
  914. if sys.platform == 'darwin':
  915. if args.build_mac_arm or platform.machine() == 'arm64':
  916. cmake_args.append('-DLLVM_DEFAULT_TARGET_TRIPLE=arm64-apple-darwin')
  917. else:
  918. cmake_args.append('-DLLVM_DEFAULT_TARGET_TRIPLE=x86_64-apple-darwin')
  919. elif sys.platform.startswith('linux'):
  920. cmake_args.append('-DLLVM_DEFAULT_TARGET_TRIPLE=x86_64-unknown-linux-gnu')
  921. elif sys.platform == 'win32':
  922. cmake_args.append('-DLLVM_DEFAULT_TARGET_TRIPLE=x86_64-pc-windows-msvc')
  923.  
  924. # TODO(crbug.com/962988): Use -DLLVM_EXTERNAL_PROJECTS instead.
  925. CreateChromeToolsShim()
  926.  
  927. if os.path.exists(LLVM_BUILD_DIR):
  928. RmTree(LLVM_BUILD_DIR)
  929. EnsureDirExists(LLVM_BUILD_DIR)
  930. os.chdir(LLVM_BUILD_DIR)
  931. RunCommand(['cmake'] + cmake_args + [os.path.join(LLVM_DIR, 'llvm')],
  932. msvc_arch='x64', env=deployment_env)
  933. CopyLibstdcpp(args, LLVM_BUILD_DIR)
  934. RunCommand(['ninja'], msvc_arch='x64')
  935.  
  936. if chrome_tools:
  937. # If any Chromium tools were built, install those now.
  938. RunCommand(['ninja', 'cr-install'], msvc_arch='x64')
  939.  
  940. if not args.build_mac_arm:
  941. VerifyVersionOfBuiltClangMatchesVERSION()
  942. VerifyZlibSupport()
  943.  
  944. if sys.platform == 'win32':
  945. rt_platform = 'windows'
  946. elif sys.platform == 'darwin':
  947. rt_platform = 'darwin'
  948. else:
  949. assert sys.platform.startswith('linux')
  950. rt_platform = 'linux'
  951. rt_lib_dst_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang', RELEASE_VERSION,
  952. 'lib', rt_platform)
  953.  
  954. # Do an out-of-tree build of compiler-rt for 32-bit Win clang_rt.profile.lib.
  955. if sys.platform == 'win32':
  956. compiler_rt_build_dir = os.path.join(LLVM_BUILD_DIR, 'compiler-rt')
  957. if os.path.isdir(compiler_rt_build_dir):
  958. RmTree(compiler_rt_build_dir)
  959. os.makedirs(compiler_rt_build_dir)
  960. os.chdir(compiler_rt_build_dir)
  961. if args.bootstrap:
  962. # The bootstrap compiler produces 64-bit binaries by default.
  963. cflags += ['-m32']
  964. cxxflags += ['-m32']
  965.  
  966. compiler_rt_args = base_cmake_args + [
  967. '-DCMAKE_C_FLAGS=' + ' '.join(cflags),
  968. '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags),
  969. '-DCMAKE_EXE_LINKER_FLAGS=' + ' '.join(ldflags),
  970. '-DCMAKE_SHARED_LINKER_FLAGS=' + ' '.join(ldflags),
  971. '-DCMAKE_MODULE_LINKER_FLAGS=' + ' '.join(ldflags),
  972. '-DCOMPILER_RT_BUILD_BUILTINS=OFF',
  973. '-DCOMPILER_RT_BUILD_CRT=OFF',
  974. '-DCOMPILER_RT_BUILD_LIBFUZZER=OFF',
  975. '-DCOMPILER_RT_BUILD_MEMPROF=OFF',
  976. '-DCOMPILER_RT_BUILD_ORC=OFF',
  977. '-DCOMPILER_RT_BUILD_PROFILE=ON',
  978. '-DCOMPILER_RT_BUILD_SANITIZERS=OFF',
  979. '-DCOMPILER_RT_BUILD_XRAY=OFF',
  980. ]
  981. RunCommand(['cmake'] + compiler_rt_args +
  982. [os.path.join(LLVM_DIR, 'llvm')],
  983. msvc_arch='x86', env=deployment_env)
  984. RunCommand(['ninja', 'compiler-rt'], msvc_arch='x86')
  985.  
  986. # Copy select output to the main tree.
  987. rt_lib_src_dir = os.path.join(compiler_rt_build_dir, 'lib', 'clang',
  988. RELEASE_VERSION, 'lib', rt_platform)
  989. # Static and dynamic libraries:
  990. CopyDirectoryContents(rt_lib_src_dir, rt_lib_dst_dir)
  991.  
  992. if args.with_android:
  993. # TODO(thakis): Now that the NDK uses clang, try to build all archs in
  994. # one LLVM build instead of building 3 times.
  995. toolchain_dir = ANDROID_NDK_DIR + '/toolchains/llvm/prebuilt/linux-x86_64'
  996. for target_arch in ['aarch64', 'arm', 'i686']:
  997. # Build compiler-rt runtimes needed for Android in a separate build tree.
  998. build_dir = os.path.join(LLVM_BUILD_DIR, 'android-' + target_arch)
  999. if not os.path.exists(build_dir):
  1000. os.mkdir(os.path.join(build_dir))
  1001. os.chdir(build_dir)
  1002. target_triple = target_arch
  1003. if target_arch == 'arm':
  1004. target_triple = 'armv7'
  1005. api_level = '21' if target_arch == 'aarch64' else '19'
  1006. target_triple += '-linux-android' + api_level
  1007. cflags = [
  1008. '--target=' + target_triple,
  1009. '--sysroot=%s/sysroot' % toolchain_dir,
  1010. '--gcc-toolchain=' + toolchain_dir,
  1011. # android_ndk/toolchains/llvm/prebuilt/linux-x86_64/aarch64-linux-android/bin/ld
  1012. # depends on a newer version of libxml2.so than what's available on
  1013. # the bots. To make things work, use our just-built lld as linker.
  1014. '-fuse-ld=lld',
  1015. # Clang defaults to compiler-rt when targeting android after
  1016. # a478b0a199f4. Stick with libgcc for now. (crbug.com/1184398).
  1017. '--rtlib=libgcc',
  1018. ]
  1019. android_args = base_cmake_args + [
  1020. '-DCMAKE_C_COMPILER=' + os.path.join(LLVM_BUILD_DIR, 'bin/clang'),
  1021. '-DCMAKE_CXX_COMPILER=' + os.path.join(LLVM_BUILD_DIR, 'bin/clang++'),
  1022. '-DLLVM_CONFIG_PATH=' + os.path.join(LLVM_BUILD_DIR, 'bin/llvm-config'),
  1023. '-DCMAKE_C_FLAGS=' + ' '.join(cflags),
  1024. '-DCMAKE_CXX_FLAGS=' + ' '.join(cflags),
  1025. '-DCMAKE_ASM_FLAGS=' + ' '.join(cflags),
  1026. '-DCOMPILER_RT_BUILD_BUILTINS=OFF',
  1027. '-DCOMPILER_RT_BUILD_CRT=OFF',
  1028. '-DCOMPILER_RT_BUILD_LIBFUZZER=OFF',
  1029. '-DCOMPILER_RT_BUILD_MEMPROF=OFF',
  1030. '-DCOMPILER_RT_BUILD_ORC=OFF',
  1031. '-DCOMPILER_RT_BUILD_PROFILE=ON',
  1032. '-DCOMPILER_RT_BUILD_SANITIZERS=ON',
  1033. '-DCOMPILER_RT_BUILD_XRAY=OFF',
  1034. '-DSANITIZER_CXX_ABI=libcxxabi',
  1035. '-DCMAKE_SHARED_LINKER_FLAGS=-Wl,-u__cxa_demangle',
  1036. '-DANDROID=1']
  1037. RunCommand(['cmake'] + android_args + [COMPILER_RT_DIR])
  1038.  
  1039. # We use ASan, UBSan, coverage, and PGO on the various Android targets.
  1040. # Only build HWASan for AArch64.
  1041. libs_want = [
  1042. 'lib/linux/libclang_rt.asan-{0}-android.so',
  1043. 'lib/linux/libclang_rt.ubsan_standalone-{0}-android.so',
  1044. 'lib/linux/libclang_rt.profile-{0}-android.a',
  1045. ]
  1046. if target_arch == 'aarch64':
  1047. libs_want += ['lib/linux/libclang_rt.hwasan-{0}-android.so']
  1048. libs_want = [lib.format(target_arch) for lib in libs_want]
  1049. RunCommand(['ninja'] + libs_want)
  1050.  
  1051. # And copy them into the main build tree.
  1052. for p in libs_want:
  1053. shutil.copy(p, rt_lib_dst_dir)
  1054.  
  1055. if args.with_fuchsia:
  1056. # Fuchsia links against libclang_rt.builtins-<arch>.a instead of libgcc.a.
  1057. for target_arch in ['aarch64', 'x86_64']:
  1058. fuchsia_arch_name = {'aarch64': 'arm64', 'x86_64': 'x64'}[target_arch]
  1059. toolchain_dir = os.path.join(
  1060. FUCHSIA_SDK_DIR, 'arch', fuchsia_arch_name, 'sysroot')
  1061. # Build clang_rt runtime for Fuchsia in a separate build tree.
  1062. build_dir = os.path.join(LLVM_BUILD_DIR, 'fuchsia-' + target_arch)
  1063. if not os.path.exists(build_dir):
  1064. os.mkdir(os.path.join(build_dir))
  1065. os.chdir(build_dir)
  1066. target_spec = target_arch + '-unknown-fuchsia'
  1067. if args.build_mac_arm:
  1068. # Just-built clang can't run (it's an arm binary on an intel host), so
  1069. # use the bootstrap compiler instead.
  1070. host_path = LLVM_BOOTSTRAP_INSTALL_DIR
  1071. else:
  1072. host_path = LLVM_BUILD_DIR
  1073. # TODO(thakis): Might have to pass -B here once sysroot contains
  1074. # binaries (e.g. gas for arm64?)
  1075. fuchsia_args = base_cmake_args + [
  1076. '-DCMAKE_C_COMPILER=' + os.path.join(host_path, 'bin/clang'),
  1077. '-DCMAKE_CXX_COMPILER=' + os.path.join(host_path, 'bin/clang++'),
  1078. '-DCMAKE_LINKER=' + os.path.join(host_path, 'bin/clang'),
  1079. '-DCMAKE_AR=' + os.path.join(host_path, 'bin/llvm-ar'),
  1080. '-DLLVM_CONFIG_PATH=' + os.path.join(host_path, 'bin/llvm-config'),
  1081. '-DCMAKE_SYSTEM_NAME=Fuchsia',
  1082. '-DCMAKE_CXX_COMPILER_TARGET=' + target_spec,
  1083. '-DCMAKE_C_COMPILER_TARGET=' + target_spec,
  1084. '-DCMAKE_ASM_COMPILER_TARGET=' + target_spec,
  1085. '-DCOMPILER_RT_BUILD_BUILTINS=ON',
  1086. '-DCOMPILER_RT_BUILD_CRT=OFF',
  1087. '-DCOMPILER_RT_BUILD_LIBFUZZER=OFF',
  1088. '-DCOMPILER_RT_BUILD_MEMPROF=OFF',
  1089. '-DCOMPILER_RT_BUILD_ORC=OFF',
  1090. '-DCOMPILER_RT_BUILD_PROFILE=OFF',
  1091. '-DCOMPILER_RT_BUILD_SANITIZERS=OFF',
  1092. '-DCOMPILER_RT_BUILD_XRAY=OFF',
  1093. '-DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON',
  1094. '-DCMAKE_SYSROOT=%s' % toolchain_dir,
  1095. # TODO(thakis|scottmg): Use PER_TARGET_RUNTIME_DIR for all platforms.
  1096. # https://crbug.com/882485.
  1097. '-DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON',
  1098.  
  1099. # These are necessary because otherwise CMake tries to build an
  1100. # executable to test to see if the compiler is working, but in doing so,
  1101. # it links against the builtins.a that we're about to build.
  1102. '-DCMAKE_CXX_COMPILER_WORKS=ON',
  1103. '-DCMAKE_C_COMPILER_WORKS=ON',
  1104. '-DCMAKE_ASM_COMPILER_WORKS=ON',
  1105. ]
  1106. RunCommand(['cmake'] +
  1107. fuchsia_args +
  1108. [os.path.join(COMPILER_RT_DIR, 'lib', 'builtins')])
  1109. builtins_a = 'libclang_rt.builtins.a'
  1110. RunCommand(['ninja', builtins_a])
  1111.  
  1112. # And copy it into the main build tree.
  1113. fuchsia_lib_dst_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang',
  1114. RELEASE_VERSION, 'lib', target_spec)
  1115. if not os.path.exists(fuchsia_lib_dst_dir):
  1116. os.makedirs(fuchsia_lib_dst_dir)
  1117. CopyFile(os.path.join(build_dir, 'lib', target_spec, builtins_a),
  1118. fuchsia_lib_dst_dir)
  1119.  
  1120. # Build the Fuchsia profile and asan runtimes. This is done after the rt
  1121. # builtins have been created because the CMake build runs link checks that
  1122. # require that the builtins already exist to succeed.
  1123. # TODO(thakis): Figure out why this doesn't build with the stage0
  1124. # compiler in arm cross builds.
  1125. if target_arch == 'x86_64' and not args.build_mac_arm:
  1126. fuchsia_args.extend([
  1127. '-DCOMPILER_RT_BUILD_BUILTINS=OFF',
  1128. '-DCOMPILER_RT_BUILD_PROFILE=ON',
  1129. ])
  1130. # Build the asan runtime only on non-Mac platforms. Macs are excluded
  1131. # because the asan install changes library RPATHs which CMake only
  1132. # supports on ELF platforms and MacOS uses Mach-O instead of ELF.
  1133. if sys.platform != 'darwin':
  1134. fuchsia_args.extend([
  1135. '-DCOMPILER_RT_BUILD_SANITIZERS=ON',
  1136. '-DSANITIZER_NO_UNDEFINED_SYMBOLS=OFF',
  1137. ])
  1138. build_phase2_dir = os.path.join(LLVM_BUILD_DIR,
  1139. 'fuchsia-phase2-' + target_arch)
  1140. if not os.path.exists(build_phase2_dir):
  1141. os.mkdir(os.path.join(build_phase2_dir))
  1142. os.chdir(build_phase2_dir)
  1143. RunCommand(['cmake'] +
  1144. fuchsia_args +
  1145. [COMPILER_RT_DIR])
  1146. profile_a = 'libclang_rt.profile.a'
  1147. asan_so = 'libclang_rt.asan.so'
  1148. ninja_command = ['ninja', profile_a]
  1149. if sys.platform != 'darwin':
  1150. ninja_command.append(asan_so)
  1151. RunCommand(ninja_command)
  1152. CopyFile(os.path.join(build_phase2_dir, 'lib', target_spec, profile_a),
  1153. fuchsia_lib_dst_dir)
  1154. if sys.platform != 'darwin':
  1155. CopyFile(os.path.join(build_phase2_dir, 'lib', target_spec, asan_so),
  1156. fuchsia_lib_dst_dir)
  1157.  
  1158. # Run tests.
  1159. if (not args.build_mac_arm and
  1160. (args.run_tests or args.llvm_force_head_revision)):
  1161. RunCommand(['ninja', '-C', LLVM_BUILD_DIR, 'cr-check-all'], msvc_arch='x64')
  1162.  
  1163. if not args.build_mac_arm and args.run_tests:
  1164. test_targets = [ 'check-all' ]
  1165. if sys.platform == 'darwin':
  1166. # TODO(thakis): Run check-all on Darwin too, https://crbug.com/959361
  1167. test_targets = [ 'check-llvm', 'check-clang', 'check-lld' ]
  1168. RunCommand(['ninja', '-C', LLVM_BUILD_DIR] + test_targets, msvc_arch='x64')
  1169.  
  1170. WriteStampFile(PACKAGE_VERSION, STAMP_FILE)
  1171. WriteStampFile(PACKAGE_VERSION, FORCE_HEAD_REVISION_FILE)
  1172. print('Clang build was successful.')
  1173. return 0
  1174.  
  1175.  
  1176. if __name__ == '__main__':
  1177. sys.exit(main())
  1178.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement