-
-
Save vincent-picaud/691b00ec1f91cc29070c5644bc9070e8 to your computer and use it in GitHub Desktop.
Basics of generating a compile_commands.json file with Bazel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
py_binary( | |
name = 'generate_compile_command', | |
srcs = [ | |
'generate_compile_command.py', | |
], | |
deps = [ | |
'//third_party/bazel:extra_actions_proto_py', | |
], | |
) | |
action_listener( | |
name = 'generate_compile_commands_listener', | |
visibility = ['//visibility:public'], | |
mnemonics = [ | |
'CppCompile', | |
], | |
extra_actions = [':generate_compile_commands_action'], | |
) | |
extra_action( | |
name = 'generate_compile_commands_action', | |
tools = [ | |
':generate_compile_command', | |
], | |
out_templates = [ | |
'$(ACTION_ID)_compile_command', | |
], | |
cmd = '$(location :generate_compile_command) $(EXTRA_ACTION_FILE)' + | |
' $(output $(ACTION_ID)_compile_command)', | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is the implementation of a Bazel extra_action which genenerates | |
# _compile_command files for generate_compile_commands.py to consume. | |
import sys | |
import third_party.bazel.protos.extra_actions_base_pb2 as extra_actions_base_pb2 | |
def _get_cpp_command(cpp_compile_info): | |
compiler = cpp_compile_info.tool | |
options = ' '.join(cpp_compile_info.compiler_option) | |
source = cpp_compile_info.source_file | |
output = cpp_compile_info.output_file | |
return '%s %s -c %s -o %s' % (compiler, options, source, output), source | |
def main(argv): | |
action = extra_actions_base_pb2.ExtraActionInfo() | |
with open(argv[1], 'rb') as f: | |
action.MergeFromString(f.read()) | |
command, source_file = _get_cpp_command( | |
action.Extensions[extra_actions_base_pb2.CppCompileInfo.cpp_compile_info]) | |
with open(argv[2], 'w') as f: | |
f.write(command) | |
f.write('\0') | |
f.write(source_file) | |
if __name__ == '__main__': | |
sys.exit(main(sys.argv)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
# This reads the _compile_command files :generate_compile_commands_action | |
# generates a outputs a compile_commands.json file at the top of the source | |
# tree for things like clang-tidy to read. | |
# Overall usage directions: run bazel with | |
# --experimental_action_listener=//tools/actions:generate_compile_commands_listener | |
# for all the files you want to use clang-tidy with and then run this script. | |
# Afer that, `clang-tidy build_tests/gflags.cc` should work. | |
import sys | |
import pathlib | |
import os.path | |
import subprocess | |
''' | |
Args: | |
path: The pathlib.Path to _compile_command file. | |
command_directory: The directory commands are run from. | |
Returns a string to stick in compile_commands.json. | |
''' | |
def _get_command(path, command_directory): | |
with path.open('r') as f: | |
contents = f.read().split('\0') | |
if len(contents) != 2: | |
# Old/incomplete file or something; silently ignore it. | |
return None | |
return '''{ | |
"directory": "%s", | |
"command": "%s", | |
"file": "%s", | |
},''' % (command_directory, contents[0].replace('"', '\\"'), contents[1]) | |
''' | |
Args: | |
path: A directory pathlib.Path to look for _compile_command files under. | |
command_directory: The directory commands are run from. | |
Yields strings to stick in compile_commands.json. | |
''' | |
def _get_compile_commands(path, command_directory): | |
for f in path.iterdir(): | |
if f.is_dir(): | |
yield from _get_compile_commands(f, command_directory) | |
elif f.name.endswith('_compile_command'): | |
command = _get_command(f, command_directory) | |
if command: | |
yield command | |
def main(argv): | |
source_path = os.path.join(os.path.dirname(__file__), '../..') | |
action_outs = os.path.join(source_path, | |
'bazel-bin/../extra_actions', | |
'tools/actions/generate_compile_commands_action') | |
command_directory = subprocess.check_output( | |
('bazel', 'info', 'execution_root'), | |
cwd=source_path).decode('utf-8').rstrip() | |
commands = _get_compile_commands(pathlib.Path(action_outs), command_directory) | |
with open(os.path.join(source_path, 'compile_commands.json'), 'w') as f: | |
f.write('[') | |
for command in commands: | |
f.write(command) | |
f.write(']') | |
if __name__ == '__main__': | |
sys.exit(main(sys.argv)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment