diff --git a/docs/users/how_tos/compilation_database.md b/docs/users/how_tos/compilation_database.md new file mode 100644 index 0000000000000..1cadd59180e57 --- /dev/null +++ b/docs/users/how_tos/compilation_database.md @@ -0,0 +1,47 @@ +--- +id: compilation_database +title: Compilation databases +--- + +# Generating compilation databases + +You can generate compilation databases for consumption by tools such as +clangd and clang-tidy by running the following BXL script: + +```sh +buck2 bxl prelude//cxx/tools/compilation_database.bxl:generate -- --targets ... +``` + +The script will generate a compilation database for all source and +header inputs to the targets listed on the command line. The path to the +database is printed to `stdout`. Note that files that are referenced by +multiple targets will have multiple associated entries in the database, +which may not be desirable in all circumstances. For example, clang-tidy +runs analysis for each entry sequentially when the file being linted has +several entries. + +It is common to symlink the resulting data at the root of the +repository: + +```sh +ln -sf $(buck2 bxl prelude//cxx/tools/compilation_database.bxl:generate -- --targets ...) $(git rev-parse --show-toplevel) +``` + +Since the path to the script is rather long, consider setting up an +alias in your repository: + +```python +# `comp_db.bxl` + +load("@prelude//cxx/tools/compilation_database.bxl:generate", "generate") + +gen = generate +``` + +```sh +ln -sf $(buck2 bxl comp_db.bxl:gen -- --targets ...) $(git rev-parse --show-toplevel) +``` + +Providing better ergonomics for BXL scripts (such as enabling something +like `buck2 comp_db`) is being discussed at +. diff --git a/prelude/cxx/tools/compilation_database.bxl b/prelude/cxx/tools/compilation_database.bxl new file mode 100644 index 0000000000000..a7ae079addfd3 --- /dev/null +++ b/prelude/cxx/tools/compilation_database.bxl @@ -0,0 +1,44 @@ +load("@prelude//cxx/comp_db.bzl", "CxxCompilationDbInfo") +load("@prelude//cxx/compile.bzl", "CxxSrcCompileCommand") +load("@prelude//utils:utils.bzl", "flatten") + +def _make_entry(ctx: bxl.Context, compile_command: CxxSrcCompileCommand) -> dict: + args = compile_command.cxx_compile_cmd.base_compile_cmd.copy() + + # This prevents clangd from jumping into `buck-out` when using Go To + # Definition, which significantly improces user experience. + args.add(["-I", "."]) + args.add(compile_command.cxx_compile_cmd.argsfile.cmd_form) + args.add(compile_command.args) + ctx.output.ensure_multiple(args) + + return { + "arguments": args, + "directory": ctx.fs.abs_path_unsafe(ctx.root()), + "file": compile_command.src, + } + +def _impl(ctx: bxl.Context): + actions = ctx.bxl_actions().actions + targets = flatten(ctx.cli_args.targets) + + db = [] + for name, target in ctx.analysis(ctx.configured_targets(targets)).items(): + comp_db_info = target.providers().get(CxxCompilationDbInfo) + if comp_db_info: + db += [_make_entry(ctx, cc) for cc in comp_db_info.info.values()] + + db_file = actions.declare_output("compile_commands.json") + actions.write_json(db_file.as_output(), db, with_inputs = True, pretty = True) + ctx.output.print(ctx.output.ensure(db_file)) + +generate = bxl_main( + doc = "Generate a compilation database for a set of targets and print its path to stdout", + impl = _impl, + cli_args = { + "targets": cli_args.list( + cli_args.target_expr(), + doc = "Targets to generate the database for", + ), + }, +)