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 6import argparse 7import json 8import os 9import re 10import shlex 11import sys 12 13script_dir = os.path.dirname(os.path.realpath(__file__)) 14tool_dir = os.path.abspath(os.path.join(script_dir, '../pylib')) 15sys.path.insert(0, tool_dir) 16 17from clang import compile_db 18 19_PROBABLY_CLANG_RE = re.compile(r'clang(?:\+\+)?$') 20 21 22def 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 40def 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 72def 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 86if __name__ == '__main__': 87 sys.exit(main()) 88