Brian Silverman | d4aea1d | 2015-12-09 00:24:18 -0500 | [diff] [blame] | 1 | #!/usr/bin/python3 |
| 2 | |
| 3 | # This reads the _compile_command files :generate_compile_commands_action |
| 4 | # generates a outputs a compile_commands.json file at the top of the source |
| 5 | # tree for things like clang-tidy to read. |
| 6 | |
| 7 | # Overall usage directions: run bazel with |
| 8 | # --experimental_action_listener=//tools/actions:generate_compile_commands_listener |
| 9 | # for all the files you want to use clang-tidy with and then run this script. |
| 10 | # Afer that, `clang-tidy build_tests/gflags.cc` should work. |
| 11 | |
| 12 | import sys |
| 13 | import pathlib |
| 14 | import os.path |
| 15 | import subprocess |
| 16 | |
| 17 | ''' |
| 18 | Args: |
| 19 | path: The pathlib.Path to _compile_command file. |
| 20 | command_directory: The directory commands are run from. |
| 21 | |
| 22 | Returns a string to stick in compile_commands.json. |
| 23 | ''' |
| 24 | def _get_command(path, command_directory): |
| 25 | with path.open('r') as f: |
| 26 | contents = f.read().split('\0') |
| 27 | if len(contents) != 2: |
| 28 | # Old/incomplete file or something; silently ignore it. |
| 29 | return None |
| 30 | return '''{ |
| 31 | "directory": "%s", |
| 32 | "command": "%s", |
| 33 | "file": "%s", |
| 34 | },''' % (command_directory, contents[0].replace('"', '\\"'), contents[1]) |
| 35 | |
| 36 | ''' |
| 37 | Args: |
| 38 | path: A directory pathlib.Path to look for _compile_command files under. |
| 39 | command_directory: The directory commands are run from. |
| 40 | |
| 41 | Yields strings to stick in compile_commands.json. |
| 42 | ''' |
| 43 | def _get_compile_commands(path, command_directory): |
| 44 | for f in path.iterdir(): |
| 45 | if f.is_dir(): |
| 46 | yield from _get_compile_commands(f, command_directory) |
| 47 | elif f.name.endswith('_compile_command'): |
| 48 | command = _get_command(f, command_directory) |
| 49 | if command: |
| 50 | yield command |
| 51 | |
| 52 | def main(argv): |
| 53 | source_path = os.path.join(os.path.dirname(__file__), '../..') |
| 54 | action_outs = os.path.join(source_path, |
| 55 | 'bazel-bin/../extra_actions', |
| 56 | 'tools/actions/generate_compile_commands_action') |
| 57 | command_directory = subprocess.check_output( |
| 58 | ('bazel', 'info', 'execution_root'), |
| 59 | cwd=source_path).decode('utf-8').rstrip() |
| 60 | commands = _get_compile_commands(pathlib.Path(action_outs), command_directory) |
| 61 | with open(os.path.join(source_path, 'compile_commands.json'), 'w') as f: |
| 62 | f.write('[') |
| 63 | for command in commands: |
| 64 | f.write(command) |
| 65 | f.write(']') |
| 66 | |
| 67 | if __name__ == '__main__': |
| 68 | sys.exit(main(sys.argv)) |