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