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