Skip to content

Commit

Permalink
Add a BXL script for generating compilation databases
Browse files Browse the repository at this point in the history
This is a diffent approach than facebook#510. The
main differences are:
- All required dependencies, such as generated code, are materialized, so that
  tools that use the compilation database work can find those and work properly.
- Files that are included in multiple targets result in multiple entries in the
  compilation database.

Closes facebook#307
  • Loading branch information
cbarrete committed Nov 15, 2024
1 parent 639bb03 commit 35b5804
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 0 deletions.
47 changes: 47 additions & 0 deletions docs/users/how_tos/compilation_database.md
Original file line number Diff line number Diff line change
@@ -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
<https://github.com/facebook/buck2/issues/86>.
44 changes: 44 additions & 0 deletions prelude/cxx/tools/compilation_database.bxl
Original file line number Diff line number Diff line change
@@ -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",
),
},
)

0 comments on commit 35b5804

Please sign in to comment.