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', required=True, help='path to the compile database')
     26   parser.add_argument('--generate-compdb',
     27                       action='store_true',
     28                       help='regenerate the compile database')
     29   parser.add_argument('--prefix',
     30                       help='optional prefix to prepend, e.g. --prefix=lldb')
     31   parser.add_argument(
     32       '--compiler',
     33       help='compiler to override the compiler specied in the compile db')
     34   parser.add_argument('--suffix',
     35                       help='optional suffix to append, e.g.' +
     36                       ' --suffix="-Xclang -ast-dump -fsyntax-only"')
     37   parser.add_argument('target_file', help='file to build')
     38   return parser.parse_args()
     39 
     40 
     41 def BuildIt(record, prefix, compiler, suffix):
     42   """Builds the file in the provided compile DB record.
     43 
     44   Args:
     45     prefix: Optional prefix to prepend to the build command.
     46     compiler: Optional compiler to override the compiler specified the record.
     47     suffix: Optional suffix to append to the build command.
     48   """
     49   raw_args = shlex.split(record['command'])
     50   # The compile command might have some goop in front of it, e.g. if the build
     51   # is using goma, so shift arguments off the front until raw_args[0] looks like
     52   # a clang invocation.
     53   while raw_args:
     54     if _PROBABLY_CLANG_RE.search(raw_args[0]):
     55       break
     56     raw_args = raw_args[1:]
     57   if not raw_args:
     58     print 'error: command %s does not appear to invoke clang!' % record[
     59         'command']
     60     return 2
     61   args = []
     62   if prefix:
     63     args.extend(shlex.split(prefix))
     64   if compiler:
     65     raw_args[0] = compiler
     66   args.extend(raw_args)
     67   if suffix:
     68     args.extend(shlex.split(suffix))
     69   print 'Running %s' % ' '.join(args)
     70   os.execv(args[0], args)
     71 
     72 
     73 def main():
     74   args = ParseArgs()
     75   os.chdir(args.p)
     76   if args.generate_compdb:
     77     with open('compile_commands.json', 'w') as f:
     78       f.write(compile_db.GenerateWithNinja('.'))
     79   db = compile_db.Read('.')
     80   for record in db:
     81     if os.path.normpath(os.path.join(args.p, record[
     82         'file'])) == args.target_file:
     83       return BuildIt(record, args.prefix, args.compiler, args.suffix)
     84   print 'error: could not find %s in compile DB!' % args.target_file
     85   return 1
     86 
     87 
     88 if __name__ == '__main__':
     89   sys.exit(main())
     90