Skip to content

Instantly share code, notes, and snippets.

@astocko
Forked from bsilver8192/BUILD
Created November 8, 2016 17:48
Show Gist options
  • Save astocko/5c9138391f3bc0044ca08aa9d5716add to your computer and use it in GitHub Desktop.
Save astocko/5c9138391f3bc0044ca08aa9d5716add to your computer and use it in GitHub Desktop.
Basics of generating a compile_commands.json file with Bazel
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 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))
#!/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