Home | History | Annotate | Download | only in scripts
      1 #!/usr/bin/env python
      2 # Copyright 2016 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 import argparse
      7 import json
      8 import os
      9 import re
     10 import shlex
     11 import sys
     12 
     13 script_dir = os.path.dirname(os.path.realpath(__file__))
     14 tool_dir = os.path.abspath(os.path.join(script_dir, '../pylib'))
     15 sys.path.insert(0, tool_dir)
     16 
     17 from clang import compile_db
     18 
     19 _PROBABLY_CLANG_RE = re.compile(r'clang(?:\+\+)?$')
     20 
     21 
     22 def ParseArgs():
     23   parser = argparse.ArgumentParser(
     24       description='Utility to build one Chromium file for debugging clang')
     25   parser.add_argument('-p', default='.', help='path to the compile database')
     26   parser.add_argument('--generate-compdb',
     27                       help='regenerate the compile database')
     28   parser.add_argument('--prefix',
     29                       help='optional prefix to prepend, e.g. --prefix=lldb')
     30   parser.add_argument(
     31       '--compiler',
     32       help='compiler to override the compiler specied in the compile db')
     33   parser.add_argument('--suffix',
     34                       help='optional suffix to append, e.g.' +
     35                       ' --suffix="-Xclang -ast-dump -fsyntax-only"')
     36   parser.add_argument('target_file', help='file to build')
     37   return parser.parse_args()
     38 
     39 
     40 def BuildIt(record, prefix, compiler, suffix):
     41   """Builds the file in the provided compile DB record.
     42 
     43   Args:
     44     prefix: Optional prefix to prepend to the build command.
     45     compiler: Optional compiler to override the compiler specified the record.
     46     suffix: Optional suffix to append to the build command.
     47   """
     48   raw_args = shlex.split(record['command'])
     49   # The compile command might have some goop in front of it, e.g. if the build
     50   # is using goma, so shift arguments off the front until raw_args[0] looks like
     51   # a clang invocation.
     52   while raw_args:
     53     if _PROBABLY_CLANG_RE.search(raw_args[0]):
     54       break
     55     raw_args = raw_args[1:]
     56   if not raw_args:
     57     print 'error: command %s does not appear to invoke clang!' % record[
     58         'command']
     59     return 2
     60   args = []
     61   if prefix:
     62     args.extend(shlex.split(prefix))
     63   if compiler:
     64     raw_args[0] = compiler
     65   args.extend(raw_args)
     66   if suffix:
     67     args.extend(shlex.split(suffix))
     68   print 'Running %s' % ' '.join(args)
     69   os.execv(args[0], args)
     70 
     71 
     72 def main():
     73   args = ParseArgs()
     74   os.chdir(args.p)
     75   if args.generate_compdb:
     76     compile_db.GenerateWithNinja('.')
     77   db = compile_db.Read('.')
     78   for record in db:
     79     if os.path.normpath(os.path.join(args.p, record[
     80         'file'])) == args.target_file:
     81       return BuildIt(record, args.prefix, args.compiler, args.suffix)
     82   print 'error: could not find %s in compile DB!' % args.target_file
     83   return 1
     84 
     85 
     86 if __name__ == '__main__':
     87   sys.exit(main())
     88