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"""A script for fetching LLVM monorepo and building clang-tools-extra binaries. 6 7Example: build clangd and clangd-indexer 8 9 tools/clang/scripts/build_clang_tools_extra.py --fetch out/Release clangd \ 10 clangd-indexer 11""" 12 13from __future__ import print_function 14 15import argparse 16import errno 17import os 18import subprocess 19import sys 20import update 21 22 23def GetCheckoutDir(out_dir): 24 """Returns absolute path to the checked-out llvm repo.""" 25 return os.path.join(out_dir, 'tools', 'clang', 'third_party', 'llvm') 26 27 28def GetBuildDir(out_dir): 29 return os.path.join(GetCheckoutDir(out_dir), 'build') 30 31 32def CreateDirIfNotExists(dir): 33 if not os.path.exists(dir): 34 os.makedirs(dir) 35 36 37def FetchLLVM(checkout_dir, revision): 38 """Clone llvm repo into |out_dir| or update if it already exists.""" 39 CreateDirIfNotExists(os.path.dirname(checkout_dir)) 40 41 try: 42 # First, try to clone the repo. 43 args = [ 44 'git', 45 'clone', 46 'https://github.com/llvm/llvm-project.git', 47 checkout_dir, 48 ] 49 subprocess.check_call(args, shell=sys.platform == 'win32') 50 except subprocess.CalledProcessError: 51 # Otherwise, try to update it. 52 print('-- Attempting to update existing repo') 53 args = ['git', 'pull', '--rebase', 'origin', 'main'] 54 subprocess.check_call(args, cwd=checkout_dir, shell=sys.platform == 'win32') 55 if revision: 56 args = ['git', 'checkout', revision] 57 subprocess.check_call(args, cwd=checkout_dir, shell=sys.platform == 'win32') 58 59 60def BuildTargets(build_dir, targets): 61 """Build targets from llvm repo at |build_dir|.""" 62 CreateDirIfNotExists(build_dir) 63 64 # From that dir, run cmake 65 cmake_args = [ 66 'cmake', 67 '-GNinja', 68 '-DLLVM_ENABLE_PROJECTS=clang;clang-tools-extra', 69 '-DCMAKE_BUILD_TYPE=Release', 70 '-DLLVM_ENABLE_ASSERTIONS=On', 71 '../llvm', 72 ] 73 subprocess.check_call(cmake_args, cwd=build_dir) 74 75 ninja_commands = ['ninja'] + targets 76 subprocess.check_call(ninja_commands, cwd=build_dir) 77 78 79def main(): 80 parser = argparse.ArgumentParser(description='Build clang_tools_extra.') 81 parser.add_argument('--fetch', action='store_true', help='fetch LLVM source') 82 parser.add_argument( 83 '--revision', help='LLVM revision to use', default=update.CLANG_REVISION) 84 parser.add_argument('OUT_DIR', help='where we put the LLVM source repository') 85 parser.add_argument('TARGETS', nargs='+', help='targets being built') 86 args = parser.parse_args() 87 88 if args.fetch: 89 print('Fetching LLVM source') 90 FetchLLVM(GetCheckoutDir(args.OUT_DIR), args.revision) 91 92 print('Building targets: %s' % ', '.join(args.TARGETS)) 93 BuildTargets(GetBuildDir(args.OUT_DIR), args.TARGETS) 94 95 96if __name__ == '__main__': 97 sys.exit(main()) 98