chromium/tools/clang/scripts/build_clang_tools_extra.py

#!/usr/bin/env python3
# Copyright 2019 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""A script for fetching LLVM monorepo and building clang-tools-extra binaries.

Example: build clangd and clangd-indexer

   tools/clang/scripts/build_clang_tools_extra.py --fetch out/Release clangd \
       clangd-indexer
"""

import argparse
import errno
import os
import subprocess
import sys
import update


from build import (CheckoutGitRepo, LLVM_GIT_URL)

def GetCheckoutDir(out_dir):
  """Returns absolute path to the checked-out llvm repo."""
  return os.path.join(out_dir, 'tools', 'clang', 'third_party', 'llvm')


def GetBuildDir(out_dir):
  return os.path.join(GetCheckoutDir(out_dir), 'build')


def CreateDirIfNotExists(dir):
  if not os.path.exists(dir):
    os.makedirs(dir)


def FetchLLVM(checkout_dir, revision):
  """Clone llvm repo into |checkout_dir| or update if it already exists."""
  CreateDirIfNotExists(os.path.dirname(checkout_dir))
  cwd = os.getcwd()
  CheckoutGitRepo('LLVM monorepo', LLVM_GIT_URL, revision, checkout_dir)
  os.chdir(cwd)


def BuildTargets(build_dir, targets):
  """Build targets from llvm repo at |build_dir|."""
  CreateDirIfNotExists(build_dir)

  # From that dir, run cmake
  cmake_args = [
      'cmake',
      '-GNinja',
      '-DLLVM_ENABLE_PROJECTS=clang;clang-tools-extra',
      '-DCMAKE_BUILD_TYPE=Release',
      '-DLLVM_ENABLE_ASSERTIONS=On',
      '../llvm',
  ]
  subprocess.check_call(cmake_args, cwd=build_dir)

  ninja_commands = ['ninja'] + targets
  subprocess.check_call(ninja_commands, cwd=build_dir)


def main():
  parser = argparse.ArgumentParser(description='Build clang_tools_extra.')
  parser.add_argument('--fetch', action='store_true', help='fetch LLVM source')
  parser.add_argument(
      '--revision', help='LLVM revision to use', default=update.CLANG_REVISION)
  parser.add_argument('OUT_DIR', help='where we put the LLVM source repository')
  parser.add_argument('TARGETS', nargs='+', help='targets being built')
  args = parser.parse_args()

  if args.fetch:
    print('Fetching LLVM source')
    FetchLLVM(GetCheckoutDir(args.OUT_DIR), args.revision)

  print('Building targets: %s' % ', '.join(args.TARGETS))
  BuildTargets(GetBuildDir(args.OUT_DIR), args.TARGETS)


if __name__ == '__main__':
  sys.exit(main())