| #!/usr/bin/env vpython3 |
| # Copyright 2016 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| from __future__ import print_function |
| |
| import argparse |
| import json |
| import os |
| import re |
| import shlex |
| import sys |
| |
| script_dir = os.path.dirname(os.path.realpath(__file__)) |
| tool_dir = os.path.abspath(os.path.join(script_dir, '../pylib')) |
| sys.path.insert(0, tool_dir) |
| |
| from clang import compile_db |
| |
| _PROBABLY_CLANG_RE = re.compile(r'clang(?:\+\+)?$') |
| |
| |
| def ParseArgs(): |
| parser = argparse.ArgumentParser( |
| description='Utility to build one Chromium file for debugging clang') |
| parser.add_argument('-p', required=True, help='path to the compile database') |
| parser.add_argument('--generate-compdb', |
| action='store_true', |
| help='regenerate the compile database') |
| parser.add_argument('--prefix', |
| help='optional prefix to prepend, e.g. --prefix=lldb') |
| parser.add_argument( |
| '--compiler', |
| help='compiler to override the compiler specified in the compile db') |
| parser.add_argument('--suffix', |
| help='optional suffix to append, e.g.' + |
| ' --suffix="-Xclang -ast-dump -fsyntax-only"') |
| parser.add_argument('target_file', help='file to build') |
| return parser.parse_args() |
| |
| |
| def BuildIt(record, prefix, compiler, suffix): |
| """Builds the file in the provided compile DB record. |
| |
| Args: |
| prefix: Optional prefix to prepend to the build command. |
| compiler: Optional compiler to override the compiler specified the record. |
| suffix: Optional suffix to append to the build command. |
| """ |
| raw_args = shlex.split(record['command']) |
| # The compile command might have some goop in front of it, e.g. if the build |
| # is using reclient, so shift arguments off the front until raw_args[0] looks |
| # like a clang invocation. |
| while raw_args: |
| if _PROBABLY_CLANG_RE.search(raw_args[0]): |
| break |
| raw_args = raw_args[1:] |
| if not raw_args: |
| print('error: command %s does not appear to invoke clang!' % |
| record['command']) |
| return 2 |
| args = [] |
| if prefix: |
| args.extend(shlex.split(prefix)) |
| if compiler: |
| raw_args[0] = compiler |
| args.extend(raw_args) |
| if suffix: |
| args.extend(shlex.split(suffix)) |
| print('Running %s' % ' '.join(args)) |
| os.execv(args[0], args) |
| |
| |
| def main(): |
| args = ParseArgs() |
| os.chdir(args.p) |
| if args.generate_compdb: |
| with open('compile_commands.json', 'w') as f: |
| f.write(compile_db.GenerateWithNinja('.')) |
| db = compile_db.Read('.') |
| for record in db: |
| if os.path.normpath(os.path.join(args.p, record[ |
| 'file'])) == args.target_file: |
| return BuildIt(record, args.prefix, args.compiler, args.suffix) |
| print('error: could not find %s in compile DB!' % args.target_file) |
| return 1 |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main()) |